Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.

...powered by haas.homelinux.net...

Inhaltsverzeichnis
1 Einleitung
2 Überblick über Python
3 Die Arbeit mit Python
4 Der interaktive Modus
5 Grundlegendes zu Python-Programmen
6 Kontrollstrukturen
7 Das Laufzeitmodell
8 Basisdatentypen
9 Benutzerinteraktion und Dateizugriff
10 Funktionen
11 Modularisierung
12 Objektorientierung
13 Weitere Spracheigenschaften
14 Mathematik
15 Strings
16 Datum und Zeit
17 Schnittstelle zum Betriebssystem
18 Parallele Programmierung
19 Datenspeicherung
20 Netzwerkkommunikation
21 Debugging
22 Distribution von Python-Projekten
23 Optimierung
24 Grafische Benutzeroberflächen
25 Python als serverseitige Programmiersprache im WWW mit Django
26 Anbindung an andere Programmiersprachen
27 Insiderwissen
28 Zukunft von Python
A Anhang
Stichwort

Download:
- ZIP, ca. 4,8 MB
Buch bestellen
Ihre Meinung?

Spacer
 <<   zurück
Python von Peter Kaiser, Johannes Ernesti
Das umfassende Handbuch - Aktuell zu Python 2.5
Buch: Python

Python
gebunden, mit CD
819 S., 39,90 Euro
Galileo Computing
ISBN 978-3-8362-1110-9
Pfeil 26 Anbindung an andere Programmiersprachen
  Pfeil 26.1 Dynamisch ladbare Bibliotheken – ctypes
    Pfeil 26.1.1 Ein einfaches Beispiel
    Pfeil 26.1.2 Die eigene Bibliothek
    Pfeil 26.1.3 Schnittstellenbeschreibung
    Pfeil 26.1.4 Verwendung des Moduls
  Pfeil 26.2 Schreiben von Extensions
    Pfeil 26.2.1 Ein einfaches Beispiel
    Pfeil 26.2.2 Exceptions
    Pfeil 26.2.3 Erzeugen der Extension
    Pfeil 26.2.4 Reference Counting
  Pfeil 26.3 Python als eingebettete Skriptsprache
    Pfeil 26.3.1 Ein einfaches Beispiel
    Pfeil 26.3.2 Ein komplexeres Beispiel
    Pfeil 26.3.3 Python-API-Referenz

»Wenn die Sprache nicht stimmt, ist das, was gesagt wird, nicht das, was gemeint ist.« – Konfuzius

26 Anbindung an andere Programmiersprachen

Dieser Abschnitt beschäftigt sich mit der Interoperabilität zwischen Python und anderen Programmiersprachen, hier ausschließlich C. Grundsätzlich gibt es dabei zwei Strategien, ein Programm zu schreiben, das Python mit einer anderen Sprache kombiniert:

1. In einem Python-Programm soll C-Code ausgeführt werden.
2. In einem C-Programm soll ein Python-Script ausgeführt werden.
       

Zu 1.: In einem größeren Projekt kann Python als sehr komfortable und gut zu wartende Sprache beispielsweise für die Programmlogik eingesetzt werden, während man einige wenige zeitkritische Algorithmen des Projekts aus Effizienzgründen in einer nicht interpretierten Sprache wie C oder C++ schreibt. Zu diesem Ansatz besprechen wir im ersten Abschnitt, wie Sie mit dem Modul ctypes der Standardbibliothek auf dynamische Bibliotheken, beispielsweise Windows-DLLs, zugreifen können. Der zweite Abschnitt soll Möglichkeiten aufzeigen, C- oder C++-Code direkt in den Python-Quelltext einzubetten.

Zu 2.: Häufig möchte man auch den umgekehrten Weg beschreiten und in einem größeren C/C++-Projekt Python als eingebettete Scriptsprache für dynamische Elemente des Programms verwenden. In einem Computerspiel könnte beispielsweise C/C++ für die hauptsächlich laufzeitkritische Hauptanwendung und die gesamte Algorithmik verwendet werden, während Python für die dynamischen Elemente des Spiels, beispielsweise Ereignisse in bestimmten Leveln oder das Verhalten verschiedener Spielfiguren, verwendet wird. Dieser Ansatz soll in Abschnitt 26.3 verfolgt werden.

Grundsätzlich benötigen Sie zum Verständnis der folgenden Kapitel zumindest rudimentäre Kenntnisse der Programmiersprache C.


Galileo Computing - Zum Seitenanfang

26.1 Dynamisch ladbare Bibliotheken – ctypes  Zur nächsten ÜberschriftZur vorigen Überschrift

Mit dem Modul ctypes ist es möglich, Funktionen einer sogenannten dynamisch ladbaren Bibliothek, im Folgenden dynamische Bibliothek genannt, aufzurufen. Zu solchen dynamischen Bibliotheken zählen beispielsweise DLL-Dateien (Dynamic Link Library) unter Windows oder SO-Dateien (Shared Object) unter Linux bzw. Unix.

Das Aufrufen von Funktionen einer dynamischen Bibliothek ist besonders dann sinnvoll, wenn bestimmte laufzeitkritische Teile eines Python-Programms in einer hardwarenäheren und damit effizienteren Programmiersprache geschrieben werden sollen oder wenn man schlicht eine in C oder C++ geschriebene Bibliothek in Python nutzen möchte.

Beachten Sie grundsätzlich, dass das Erstellen einer dynamischen Bibliothek keine Eigenschaft der Programmiersprache C ist. Im Gegenteil: Eine dynamische Bibliothek kann als eine sprachunabhängige Schnittstelle zwischen verschiedenen Programmen betrachtet werden. Es ist absolut möglich, ein Python-Programm zu schreiben, das auf eine in C geschriebene dynamische Bibliothek zugreift, die ihrerseits auf eine dynamische Bibliothek zugreift, die in Pascal geschrieben wurde. Dies gilt allerdings nur für Sprachen, die sich zu einer dynamischen Bibliothek kompilieren lassen: PHP würde beispielsweise außen vor bleiben.


Galileo Computing - Zum Seitenanfang

26.1.1 Ein einfaches Beispiel  Zur nächsten ÜberschriftZur vorigen Überschrift

Zum Einstieg in das Modul ctypes soll ein einfaches Beispiel dienen. Im Beispielprogramm soll die dynamische Bibliothek der C Runtime Library eingebunden und die darin enthaltene Funktion printf dazu genutzt werden, den Text »Hallo Welt« auszugeben. Die C Runtime Library ist unter Windows unter dem Namen msvcrt.dll und unter Unix-ähnlichen Systemen unter dem Namen libc.so.6 zu finden. Dazu betrachten wir zunächst den Quellcode des Beispielprogramms:

import ctypes 
bibliothek = ctypes.CDLL("MSVCRT") 
bibliothek.printf("Hallo Welt\n")

Zunächst wird das Modul ctypes eingebunden und dann eine Instanz der Klasse CDLL erzeugt. Eine Instanz dieser Klasse repräsentiert eine geladene dynamische Bibliothek. Beachten Sie, dass die Dateiendung .dll unter Windows weggelassen und der Name der Bibliothek großgeschrieben werden muss, wenn eine System-Bibliothek geladen werden soll. Unter Linux sähe die Instanziierung der Klasse CDLL beispielsweise so aus:

bibliothek = ctypes.CDLL("libc.so.6")

Nachdem die dynamische Bibliothek eingebunden worden ist, kann die Funktion printf wie eine Methode der CDLL-Instanz aufgerufen werden. [Beachten Sie, dass die Funktion printf nicht nach sys.stdout, sondern in den tatsächlichen stdout-Stream des Betriebssystems schreibt. Das bedeutet für Sie, dass Sie im obigen Beispiel nur dann eine Ausgabe sehen, wenn Sie das Programm in einer Python-Shell ausführen. Keine Ausgabe erscheint dagegen beispielsweise in IDLE. ] In diesem Fall können wir ganz unbesorgt einen Python-String übergeben. Behalten Sie bei der Arbeit mit ctypes aber immer im Hinterkopf, dass es teilweise große Unterschiede zwischen den Datentypen von C/C++ und denen von Python gibt. Es können also nicht alle Funktionen so einfach verwendet werden. Im Laufe dieses Kapitels werden wir noch eingehend darauf zurückkommen.


Galileo Computing - Zum Seitenanfang

26.1.2 Die eigene Bibliothek  Zur nächsten ÜberschriftZur vorigen Überschrift

An dieser Stelle soll eine dynamische Bibliothek erstellt werden, auf die wir dann in den folgenden Abschnitten zugreifen werden. Die Bibliothek ist in C geschrieben und enthält drei Funktionen mit unterschiedlich komplexer Schnittstelle. Wir werden hier nur den Quelltext der drei Funktionen zeigen, auf die wir uns in den folgenden Beispielen beziehen. Es wird keine Anleitung geben, wie Sie den C-Code zu einer dynamischen Bibliothek kompilieren können oder Ähnliches. Das ist nicht Gegenstand dieses Buches und würde sich zudem bei den verschiedensten Betriebssystemen und Entwicklungsumgebungen zum Teil stark unterscheiden. Sie finden dazu nach einer kurzen Recherche im Internet genügend Anleitungen.

// Berechnet die Fakultaet einer ganzen Zahl 
int fakultaet(int n) 
    { 
    int i; 
    int ret = 1; 
    for(i = 1; i <= n; i++) 
        ret *= i; 
    return ret; 
    }
// Berechnet die Laenge eines Vektors im R3 double veclen(double x, double y, double z) { return sqrt(x*x + y*y + z*z); }
// Bubblesort void sortiere(int *array, int len) { int i, j, tmp; for(i = 0; i < len; i++) { for(j = 0; j < i; j++) { if(array[j] > array[i]) { tmp = array[j]; array[j] = array[i]; array[i] = tmp; } } } }

Die erste Funktion, fakultaet, berechnet die Fakultät einer ganzen Zahl und gibt das Ergebnis ebenfalls in Form einer ganzen Zahl zurück. Die zweite Funktion, veclen, berechnet die Länge eines dreidimensionalen Vektors. Sie bekommt dazu die drei Koordinaten des Vektors in Form von drei Gleitkommazahlen übergeben und gibt die Länge des Vektors ebenfalls in Form einer Gleitkommazahl zurück.

Die dritte, etwas komplexere Funktion, sortiere, implementiert den sogenannten Bubblesort-Algorithmus, um ein Array von beliebig vielen ganzen Zahlen aufsteigend zu sortieren. Dazu bekommt die Funktion einen Pointer auf das erste Element sowie die Anzahl der Elemente des Arrays übergeben.

Im Folgenden gehen wir davon aus, dass der oben stehende Quellcode zu einer dynamischen Bibliothek kompiliert wurde und unter dem Namen bibliothek.dll im jeweiligen Programmverzeichnis der kommenden Beispielprogramme zu finden ist. Sollten Sie ein Unix-ähnliches Betriebssystem wie beispielsweise Linux einsetzen, müssen Sie zur Adaption der Beispielprogramme den Hinweis des vorherigen Abschnitts beachten.

Datentypen

An dieser Stelle haben wir eine fertige dynamische Bibliothek mit drei Funktionen, die wir jetzt mittels ctypes aus einem Python-Programm heraus aufrufen können. Der praktischen Umsetzung dieses Vorhabens stehen jedoch die teilweise inkompatiblen Datentypen von C und Python im Wege. Solange Instanzen der Datentypen long, int, str, unicode oder NoneType [Wenn die Instanz None an eine C-Funktion übergeben wird, kommt sie dort als NULL-Pointer an. Umgekehrt wird ein von einer C-Funktion zurückgegebener NULL-Pointer in Python zu None. ] übergeben werden, funktioniert der Funktionsaufruf einwandfrei, denn diese Instanzen können eins zu eins nach C übertragen werden. So ist beispielsweise der Aufruf der Funktion fakultaet mit keinerlei Problemen behaftet:

from ctypes import CDLL 
bib = CDLL("bibliothek.dll") 
print bib.fakultaet(5)

Doch bereits das Übergeben einer float-Instanz scheitert. Für diesen und andere Datentypen von C implementiert das Modul ctypes entsprechende Gegenstücke in Python, deren Instanzen über die Schnittstelle geschickt werden können. Die folgende Tabelle listet alle in ctypes enthaltenen Datentypen sowie ihre Entsprechungen in C und Python auf.


Tabelle 26.1  Datentypen des Moduls »ctypes«
Datentyp (ctypes) Datentyp (C) Datentyp (Python)
c_char
char

str (ein Zeichen)

c_wchar
wchar_t

unicode (ein Zeichen)

c_byte
char

int, long

c_ubyte
unsigned char

int, long

c_short
short

int, long

c_ushort
unsigned short

int, long

c_int
int

int, long

c_uint
unsigned int

int, long

c_long
long

int, long

c_ulong
unsigned long

int, long

c_longlong

__int64, long long

int, long

c_ulonglong

unsigned __int64,

unsigned long long

int, long

c_float
float

int, long

c_double
double

int, long

c_char_p
char *

str, None

c_wchar_p
wchar_t *

unicode, None

c_void_p
void *

int, long, None


All diese ctypes-Datentypen können durch Aufruf ihres Konstruktors instanziiert und mit einer Instanz des angegebenen Python-Datentyps initialisiert werden. Über das Attribut value kann der jeweilige Wert eines ctypes-Datentyps verändert werden.

>>> import ctypes 
>>> f = ctypes.c_float(1.337) 
>>> print f 
c_float(1.3370000123977661) 
>>> d = ctypes.c_double(1.337) 
>>> print d 
c_double(1.337) 
>>> s = ctypes.c_char_p("Hallo Welt") 
>>> print s 
c_char_p('Hallo Welt') 
>>> null = ctypes.c_void_p(None) 
>>> print null 
c_void_p(None)

Um ein Array eines bestimmten Datentyps anzulegen, wird der zugrunde liegende Datentyp mit der Anzahl der Elemente, die er aufnehmen soll, multipliziert. Das Ergebnis ist ein Datentyp, der das gewünschte Array speichert. Im konkreten Beispiel sieht das so aus:

>>> arraytyp = ctypes.c_int * 5 
>>> a = arraytyp(1, 5, 2, 1, 9) 
>>> a 
<__main__.c_long_Array_5 object at 0xb7af82fc>

Einen solchen Array-Typ können wir beispielsweise der Funktion sortiere übergeben, die ein Array von ganzen Zahlen sortiert:

from ctypes import CDLL, c_int 
bib = CDLL("bibliothek.dll") 
arraytyp = c_int * 10 
a = arraytyp(0,2,5,2,8,1,4,7,3,8) 
print "Vorher: ", [i for i in a] 
bib.sortiere(a, 10) 
print "Nachher: ", [i for i in a]

Die Ausgabe dieses Beispielprogramms lautet:

Vorher:  [0, 2, 5, 2, 8, 1, 4, 7, 3, 8] 
Nachher:  [0, 1, 2, 2, 3, 4, 5, 7, 8, 8]

Achtung
Häufig verlangen C-Funktionen einen Pointer auf einen String als Parameter, über den der String dann manipuliert wird. Beachten Sie unbedingt, dass Sie dann keine Instanz des Python-Datentyps str übergeben dürfen. Das liegt daran, dass str zu den unveränderlichen Datentypen gehört und auch von einer C-Funktion nicht neu beschrieben werden kann.

Um einer solchen Funktion dennoch einen beschreibbaren String zur Verfügung zu stellen, dient die Funktion create_string_buffer, die wir zusammen mit den anderen Funktionen des Moduls ctypes gegen Ende dieses Kapitels besprechen werden.



Galileo Computing - Zum Seitenanfang

26.1.3 Schnittstellenbeschreibung  Zur nächsten ÜberschriftZur vorigen Überschrift

Im folgenden Beispiel sollen die Parameter der Funktion veclen, wie von der Funktion verlangt, als Gleitkommazahlen übergeben werden.

from ctypes import CDLL, c_double 
bib = CDLL("bibliothek.dll") 
print bib.veclen(c_double(1.5), c_double (2.7), c_double (3.9))

Wird dieser Code ausgeführt, so erhält man

1080623743

als Ergebnis, was nun wirklich nicht der gesuchten Vektorlänge entspricht. Wie es zu diesem Fehler kommen konnte und wie er sich vermeiden lässt, soll Thema dieses Abschnitts sein.

Der Rückgabewert und die Parameter einer Funktion, also ihre Schnittstelle, sind in C anders als in Python an bestimmte Datentypen gebunden. Der oben beschriebene Problemfall resultiert daher, dass nach dem Laden einer dynamischen Bibliothek von ctypes angenommen wird, dass jede enthaltene C-Funktion eine ganze Zahl zurückgibt, was natürlich in vielen Fällen falsch ist. Die eigentliche Gleitkommazahl wurde also aus Unwissenheit als ganze Zahl interpretiert und entsprechend ausgegeben. Damit dies in Zukunft nicht mehr passiert, kann über das Attribut restype eines Funktionsobjekts der Datentyp des Rückgabewertes explizit angegeben werden:

from ctypes import CDLL, c_double 
bib = CDLL("bibliothek.dll") 
bib.veclen.restype = c_double 
print bib.veclen(c_double(1.5), c_double(2.7), c_double(3.9))

Bei diesem Beispielprogramm wird der Rückgabewert der C-Funktion korrekt interpretiert, wie die Ausgabe zeigt:

4.97493718553

Es wurde angesprochen, dass auch die Parameter einer Funktion in C an einen bestimmten Datentyp gebunden sind. Würden Sie beispielsweise im obigen Programm statt des Datentyps c_double Instanzen des Datentyps c_float übergeben, so würde bereits bei der Parameterübergabe ein Fehler in der Interpretation der Daten passieren, der letztlich in einem falschen Rückgabewert mündet.

Python bietet es Ihnen an, über das Attribut argtypes die Datentypen der Parameter festzulegen. Wenn das gemacht wird, werden übergebene Instanzen eines falschen Datentyps in den korrekten Datentyp konvertiert, oder es wird, wenn dies nicht möglich ist, eine ArgumentError-Exception geworfen. Im folgenden Programm wird die vollständige Schnittstelle der Funktion veclen vorgegeben:

from ctypes import CDLL, c_double 
bib = CDLL("bibliothek.dll") 
bib.veclen.restype = c_double 
bib.veclen.argtypes = [c_double, c_double, c_double] 
print bib.veclen(c_double(1.5), c_double(2.7), c_double(3.9))

Es ist zwar so, dass unter Verwendung des Moduls ctypes in vielen Fehlerfällen Exceptions geworfen werden, beispielsweise wenn zu viele, zu wenige oder die falschen Parameter übergeben werden, doch Sie sollten sich immer vergegenwärtigen, dass Sie mit ctypes viele Schutzmechanismen von Python umgehen und möglicherweise direkt im Speicher arbeiten. Es ist also durchaus möglich, unter Verwendung von ctypes den Python-Interpreter zum Absturz zu bringen. Und mit »Absturz« ist keine Exception im bisherigen Sinne gemeint, sondern ein tatsächlicher Absturz durch einen Speicherzugriffsfehler beispielsweise.


Galileo Computing - Zum Seitenanfang

26.1.4 Verwendung des Moduls  topZur vorigen Überschrift

An dieser Stelle möchten wir noch einen kurzen Überblick über die wichtigsten im Modul ctypes enthaltenen Funktionen bieten, die einem die Arbeit mit C–Funktionen teils erheblich erleichtern.

ctypes.addressof(obj)

Gibt die Speicheradresse der Instanz obj zurück. Für den Parameter obj muss dabei eine Instanz eines ctypes-Datentyps übergeben werden.

ctypes.byref(obj)

Erzeugt einen Pointer auf die Instanz obj eines ctypes-Datentyps. Der zurückgegebene Pointer kann einer C-Funktion übergeben werden.

ctypes.cast(obj, type)

Die Funktion cast bildet den Cast-Operator von C in Python ab. Die Funktion gibt eine neue Instanz des ctypes-Datentyps type zurück, die auf die gleiche Speicherstelle verweist wie obj.

ctypes.create_string_buffer(init_or_size[, size])

Diese Funktion erzeugt einen veränderlichen String-Buffer, in den aus einer C–Funktion heraus geschrieben werden kann. Zurückgegeben wird ein Array von c_char-Instanzen. Für den ersten Parameter init_or_size kann entweder eine ganze Zahl übergeben werden, die die Länge des zu erzeugenden Buffers enthält, oder ein String, mit dem der Buffer initialisiert werden soll. Beachten Sie im Falle eines Strings, dass der Buffer ein Zeichen größer gemacht wird, als der String lang ist. In dieses letzte Zeichen wird der Terminator \0 geschrieben.

Wenn für init_or_size ein String übergeben wurde, kann über den Parameter size die Größe des Buffers festgelegt werden, sofern nicht die Länge des Strings genommen werden soll.

ctypes.create_unicode_buffer(init_or_size[, size])

Diese Funktion verhält sich wie create_string_buffer, mit dem Unterschied, dass ein Array von veränderlichen c_wchar-Instanzen, also ein Unicode-Buffer, erzeugt und zurückgegeben wird.

ctypes.sizeof(obj_or_type)

Die Funktion sizeof bildet den sizeof-Operator von C auf Python ab. Zurückgegeben wird die Größe der übergebenen Instanz bzw. des übergebenen ctypes-Datentyps in Byte.

ctypes.string_at(address[, size])

Gibt den String zurück, der an der Speicheradresse address steht. Sollte der String im Speicher nicht null-terminiert sein, so kann über den Parameter size die genaue Länge des Strings übergeben werden.

Für address muss eine ganze Zahl übergeben werden, die sinnvollerweise mit addressof geholt und verändert wurde.

ctypes.wstring_at(address[, size])

Die Funktion wstring_at funktioniert wie string_at, nur für Unicode-Strings.

In diesem Abschnitt konnte Ihnen nur ein Einblick in die Funktionalität von ctypes gegeben werden. So enthält das Modul ctypes noch weitere Konzepte zur Verwendung von Pointern, Strukturen und Unions beispielsweise. Sollte Ihr Interesse am Modul ctypes geweckt worden sein und sollten Sie mehr darüber herausfinden möchten, sei Ihnen die ausführliche Python-Dokumentation zu diesem Thema ans Herz gelegt.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.






 <<   zurück
  
  Zum Katalog
Zum Katalog: Python






Python
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Linux






 Linux


Zum Katalog: Ubuntu GNU/Linux






 Ubuntu GNU/Linux


Zum Katalog: Praxisbuch Web 2.0






 Praxisbuch Web 2.0


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Praxisbuch Objektorientierung






 Praxisbuch Objektorientierung


Zum Katalog: Einstieg in SQL






 Einstieg in SQL


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für Fachinformatiker


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo