Verbindung von Python mit Delphi

Die Schlange und das Orakel
Kommentare

Wer sich schon immer eine dynamische Makro-Erweiterung für seine Delphi-Applikationen gewünscht hat, für den ist die Verbindung der Interpretersprache Python mit der RAD-Umgebung von Borland einen Blick wert.

Anwender von Microsoft Word oder Excel nutzen oft die vielfältigen Möglichkeiten, die durch Visual Basic for Applications (VBA) gegeben sind. Welcher Delphi-Entwickler hat nicht schon neidvoll auf diese Möglichkeit geschielt und sich Ähnliches auch für seine eigenen Werke gewünscht? Eine Variante, die zudem als Draufgabe noch eine reichhaltige Bibliothek für nahezu jeden denkbaren Anwendungsfall mit sich bringt, bietet sich mit der Symbiose aus der Interpretersprache Python und Object Pascal an.

Dank Python for Delphi (P4D) kann der engagierte Pascal-Programmierer die Vorzüge des Interpreters auf die gewohnte Art durch Platzierung der P4D-Komponenten auf Formularen oder Datenmodulen für sich nutzbar machen. Dabei ist das Framework keineswegs nur eine Einbahnstraße. Es ist nicht nur möglich, Python-Code aus Delphi aufzurufen, es können sowohl Variablen zwischen den beiden Welten geteilt werden als auch Delphi-Prozeduren und -Methoden aus Python heraus aufgerufen werden. Mit der neuesten Version ist sogar das Schreiben von Extensions für den Interpreter möglich, sodass das Hauptprogramm in Python geschrieben ist und lediglich zeitkritische Routinen in Delphi. Im Rahmen dieses Artikels wird diese Möglichkeit nicht weiter betrachtet, bei Interesse sollten die im Lieferumfang von P4D enthaltenen Beispiele weiterhelfen.

Python installieren
Um eine Verbindung zwischen Delphi und Python erfolgreich herzustellen, ist die Installation des Python-Interpreters [1] und von Python for Delphi [2] notwendig. Beide Pakete besitzen ein Setup, mit welchem sich die Installation problemlos vornehmen lässt. Möchte jemand Python weitergehend benutzen, so ist noch das Paket Python for Win32 [3]zu empfehlen, mit welchem nahezu jede Aufgabe unter Windows mit Python erledigt werden kann; mithilfe dieser Erweiterung wird es sogar möglich, COM-Server in Python zu erstellen.
Was ist Python?
Python [3]ist eine objektorientierte Programmiersprache, die von Guido van Rossum entwickelt wurde. Benannt wurde sie nach dessen Vorliebe für „Monthy Pythons Flying Circus“. Python besitzt eine sehr klare Struktur und bietet eine umfassende Standardbibliothek. Zahlreiche im Web verfügbare Erweiterungen decken nahezu jeden Bedarf ab. Eine Stärke von Python ist die Möglichkeit, den Interpreter in verschiedensten anderen Programmiersprachen einzubetten und so auf einfache Art und Weise zu erweitern. Ein prominentes Beispiel hierfür ist unter anderem OpenOffice.org. Mittlerweile existieren neben der in C geschriebenen Interpreterversion (CPython) auch Implementierungen in Java (Jython [4]) und .NET (IronPython [5]).

Wie funktioniert die Einbindung?

Der Python-Interpreter wird in Form einer DLL installiert, welche zum Beispiel von der Python-Kommandozeilenversion selbst verwendet wird. P4D nutzt diese DLL, um den Interpreter für Delphi nutzbar zu machen. Obwohl die Anbindung an die C-Schnittstelle von Python sehr gut dokumentiert ist, ist die damit verbundene Arbeit aus (mindestens) zwei Gründen sehr aufwendig: der große Umfang der Schnittstelle und die für Object-Pascal-Verhältnisse durch den in C geschriebenen Interpreter „ungewohnten“ Definitionen. Die Entwickler von P4D haben hier sehr gute Arbeit geleistet und die rohe Schnittstelle in ein maßgearbeitetes Komponentengewand gekleidet. Dabei finden alle Python-Versionen beginnend ab 1.4 bis zur aktuellen Version 2.4 Berücksichtigung, ebenso wie die Delphi-Versionen von Delphi 2 bis Delphi 2005. Für die optimale Nutzung der Möglichkeiten sollte man jedoch mindestens über ein Delphi 7 verfügen, so kommt man auch in den Genuss eines vereinfachten Zugriffs auf Python über Varianten.

Aufmacherbild: Hand holding a glowing crystal ball von Shutterstock / Urheberrecht: Shutter_M [ header = Seite 2: Ein erstes Beispiel ]

Ein erstes Beispiel

Nachdem nun hoffentlich die Lust auf mehr geweckt wurde, werfen wir einen Blick auf ein einfaches Beispiel, mit welchem wir eine simple Verwendung des Interpreters zeigen. Das Beispiel soll das Editieren und Anlegen einer beliebigen Anzahl von Variablen innerhalb unserer Applikation erlauben und eine ebenfalls zur Laufzeit änderbare Berechnungsvorschrift durch Python errechnen lassen, um das Ergebnis anschließend wieder mit Delphi-Mitteln darzustellen. Die notwendigen Voraussetzungen, um das Beispiel nachvollziehen zu können, sind im Kasten „Python installieren“ beschrieben.

Unser Beispiel beginnen wir wie jede Delphi-Applikation mit dem Erstellen einer neuen Anwendung. In das Formular wird aus der Python-Palette eine Komponente vom Typ PythonEngine eingefügt. Fürs Erste ist hier keine weitergehende Konfiguration notwendig, mit den Defaultwerten wird das installierte Python automatisch verwendet. Zur Eingabe der Variablen während der Laufzeit ist der Einfachheit halber ein ValueListEditor vorgesehen. Die Rechenformel ist in einer eigenen Editkomponente untergebracht. Ausgelöst wird die Übergabe der Berechnung an Python durch Klicken des Berechnungs- Buttons. Die gesamte Arbeit wird dabei im OnClick-Event ausgeführt und sieht wie folgt aus:

PythonEngine.ExecString(ValueListEditor.Strings.Text);
PythonEngine.ExecString(CalcEdit.Text);
MessageDlg(Format(‘Ergebnis: %s’, [string(VarPyth.
MainModule.CalcResult)]), mtInformation, [mbOK], 0);

In der ersten Zeile werden die im ValueList-Editor eingegebenen Variablen in einem Rutsch an den Python-Interpreter übergeben. Dies wird mittels der Methode ExecString erreicht, welcher man einen beliebigen Python-Text übergeben kann, der dann vom Interpreter abgearbeitet wird. Praktisch für uns ist, dass die vom ValueListEditor in der Eigenschaft Strings enthaltene Liste mit der Python-Deklaration von Variablen übereinstimmt (Var = Value). Nach diesem Aufruf sind unsere Variablen bereits in Python bekannt. Im nachfolgenden Aufruf wird die im Textfeld eingegebene Rechenformel an den Interpreter übergeben, dies setzt natürlich voraus, dass innerhalb des CalcEdit-Feldes ein korrektes Python-Statement eingetippt wurde. Das berechnete Ergebnis holen wir uns schließlich elegant über einen Zugriff mithilfe der eingangs bereits erwähnten Unterstützung von Varianten und stellen es dar. Das Ergebnis einer derartigen Berechnung kann man in Abbildung 1 erkennen.

Abb. 1: Ein einfaches RechenbeispielInnerhalb dieser Applikation kann nun die auf so einfache Weise gewonnene Dynamik getestet werden. Dass man auch mit dem gewählten, sehr einfachen Ansatz nicht auf Integerarithmetik beschränkt ist, zeigt sich, wenn man in das Textfeld statt der anfangs verwendeten einfachen Berechnung einen Ausdruck wie zum Beispiel CalcResult = str(A) + B eingibt und den Wert für B in Hochkomma setzt (Abb. 2). Vertippt man sich oder schleicht sich ein Syntaxfehler in die Rechenformel ein, erlebt man eine durchaus positive Überraschung (sofern man von einem Fehler positiv überrascht werden kann): Da Python ebenfalls Exceptions unterstützt, werden diese durch P4D unmittelbar in Delphi-Exceptions gewandelt und können so auch direkt in Object Pascal behandelt werden.

Abb. 2: Spielen mit Zeichenketten

[header = Seite 3: Der nächste Schritt ]

Der nächste Schritt

Das eben Gezeigte stellt eine simple Möglichkeit dar, Arbeiten an Python weiterzureichen. Allerdings wird der Aufwand, wenn man Dinge aus Python nach Delphi transferieren will, schon bedeutend höher. Zu unserem Glück bietet P4D seit neuestem auch hier einen sehr einfachen Weg, Delphi-Objekte für Python zu „wrappen“. Mit wenigen Zeilen erhält man damit den Zugriff auf die gesamte Delphi-VCL direkt aus Python heraus, ein weiteres Beispiel soll das kurz demonstrieren. Dazu erweitern wir unsere eben erstellte Anwendung mit einigen Zutaten, zu diesen zählen

  • eine neue Komponente PythonModule, sie erhält den Modulnamen „wrapper“
  • ein zusätzliches Memo, um ein Spielen mit der Applikation zu ermöglichen
  • das Verwenden der Units WrapDelphi und WrapDelphiVCL
  • das Einfügen eines neuen Feldes PyDelphiWrapper
  • etwas Delphi-Quellcode, der den Wrapper initialisiert
  • etwas Python-Quellcode, der den Zugriff aus Python zeigt
procedure TForm1.FormCreate(Sender: TObject);
var
P: PPyObject;
begin
PythoncodeMemo.Visible := False;
PyDelphiWrapper := TPyDelphiWrapper.Create(Self);
PyDelphiWrapper.Engine := PythonEngine;
PyDelphiWrapper.Module := PythonModule;
PyDelphiWrapper.Initialize;
P := PyDelphiWrapper.Wrap(Self);
PythonModule.SetVar(‘MainForm‘, P);
PythonEngine.Py_DECREF(P);
PythonEngine.ExecString(‘Language = 1‘);
end;

Beim Erzeugen des Formulars wird nun der PyDelphiWrapper erzeugt und mit der PythonEngine sowie dem neu eingefügten PythonModule verbunden, bevor er initialisiert wird (Zeilen 1 bis 9). Nun müssen nur noch jene Instanzen bekannt gemacht werden, die in Python zur Verfügung stehen sollen. Dies geschieht in den Zeilen 9 bis 11, wobei der interessanteste Teil den Aufruf von PythonModule.Set-Var betrifft. Damit wird die Delphi-Variable unter einem anzugebenden Namen (hier MainForm) innerhalb von Python zur Verfügung gestellt. Um das Ergebnis dieser Arbeit zu sehen, benötigt man nun noch etwas Python-Code, der innerhalb des Memofelds untergebracht ist.

from wrapper import MainForm

Languages = [‘Delphi‘, ‘Python‘]

if MainForm.ValueListEditor.Enabled:
MainForm.ValueListEditor.Enabled = False
Language = (Language % 2) + 1
MainForm.CalcEdit.Text = ‘CalcResult = “%s rocks!“ %
Languages[Language-1]‘

Abb. 3: PyScripter in Aktion

Abb. 3: PyScripter in Aktion

In Zeile 1 wird ähnlich einer uses-Anweisung in Delphi ein Import von verwendeten Funktionen und Deklarationen durchgeführt. In unserem Beispiel wird die in Delphi implementierte Instanz MainForm importiert. Wie in den Zeilen 5, 6 und 8 unschwer zu erkennen ist, kann man unmittelbar auf die Delphi-Instanz durchgreifen und damit Delphi aus Python heraus steuern. Dank der Python for Delphi beiliegenden Dokumentation und Tutorials kann man leicht nachvollziehen, wie man auch eigene Klassen für Python wrappen kann. Es soll hier nicht verschwiegen werden, dass die Einbindung der VCL nicht vollständig ist, ein sehr gutes Beispiel zu den Möglichkeiten zeigt die in Delphi entwickelte Python-IDE PyScripter, die sowohl in installierbarer als auch in Sourceform unter [2] bezogen werden kann.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -