import bei Python einbetten

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
monternet
User
Beiträge: 15
Registriert: Donnerstag 15. September 2011, 09:14

Hallo,

ich möchte einen Python Interpreter durch embedded Python erzeugen und dann Python Befehle ausführen. Ich muss dann eine Module aus ein Verzeichniss importieren, nämlich der Python Befehl "from xxx import yyyy". Diese Module und Verzeichniss sind kein Python Verzeichniss(d.h, nicht c:\Python\...) und nicht Python built-in Module(z.B, time, sys usw.)

Es gibt folgende Funktion:
PyImport_ImportModule()
PyImport_Import()
PyImport_AddModule()
...



Welche Python c Funktion soll ich hier dazu verwenden? Wie funktioniert hier der so genannte "name space"?


Vielen Dank im Vorraus!


VG

monternet
BlackJack

@monternet: Egal ob man das jetzt von C aus oder von Python aus importiert, würde ich als erstes mal dafür sorgen, dass das Verzeichnis mit den Modulen auf dem üblichen Weg von Python gefunden werden kann. Der Pfad dorthin müsste also in `sys.path` stehen.

Zum Importieren von C aus würde ich `PyImport_Import()` verwenden, wenn nichts dafür spricht eine Funktion auf tieferer Ebene zu verwenden.
monternet
User
Beiträge: 15
Registriert: Donnerstag 15. September 2011, 09:14

BlackJack hat geschrieben:@monternet: Egal ob man das jetzt von C aus oder von Python aus importiert, würde ich als erstes mal dafür sorgen, dass das Verzeichnis mit den Modulen auf dem üblichen Weg von Python gefunden werden kann. Der Pfad dorthin müsste also in `sys.path` stehen.

Zum Importieren von C aus würde ich `PyImport_Import()` verwenden, wenn nichts dafür spricht eine Funktion auf tieferer Ebene zu verwenden.
Hallo BlackJack,

sys.path habe ich geändert nach der Initialiesierung und zwar mit den Funktionen Py_GetPath() bekomme ich den aktuellen sys.path. Dann füge ich den Pfad des Verzeichnisses ein, in dem die zu importierende Module sich befindet. Danach mit PySys_SetPath() setze ich den Suchpfad erneut. Ist das richtig?

Du hast gemeint, dass ich PyImport_Import() verwenden könnte. d.h, wenn ich folenden Python Befehl ausführen will:

from pythontest import type

dann kann ich die Funktion so schreiben: PyImport_Import(type), wobei pythontest ist der Name des Verzeichnisses, in dem die Module type liegt.

Ist das richtig?
BlackJack

@monternet: Das mit dem Pfad ist falsch oder falls das funktioniert zumindest nicht das was ich machen würde. Ich meine tatsächlich `sys.path`; also das `sys`-Modul importieren, sich das `path`-Attribut holen, und da den Verzeichnisnamen anhängen. Oder vorne einfügen, je nach dem wie hoch die Priorität in der Suchreihenfolge sein soll.

``PyImport_Import("type")`` ist nicht äquivalent zu ``from pythontest import type``. Da fehlt ja ganz offensichtlich das `pythontest`. ``PyImport_Import("pythontest.type")`` wäre der passende Aufruf. Und damit der Import funktioniert, muss das Package `pythontest` über den Pfad (`sys.path`) zu finden sein und nicht nur das Modul `type`. Es kann sein, dass das bei einzelnen Modulen so funktioniert, aber darauf kann man sich nicht verlassen. Wenn es wichtig für das Modul ist, dass das Paket vorher importiert wurde, und damit der Code auf Package-Ebene auch ausgeführt wurde, oder wenn das Modul absolute oder relative Importe mit Bezug auf das Package macht.
monternet
User
Beiträge: 15
Registriert: Donnerstag 15. September 2011, 09:14

Vielen Dank!

Deine Tipps sind aber sehr hilfreich für mich!
monternet
User
Beiträge: 15
Registriert: Donnerstag 15. September 2011, 09:14

Hallo BlackJack,
BlackJack hat geschrieben:Ich meine tatsächlich `sys.path`; also das `sys`-Modul importieren, sich das `path`-Attribut holen, und da den Verzeichnisnamen anhängen.
Dazu habe ich in Python Doku nur die Funktionen Py_GetPath() und PySys_SetPath() gefunden. Weil die Beschreibung für Py_GetPath() ist:
Return the default module search path; this is computed from the program name (set by Py_SetProgramName() above) and some environment variables. The returned string consists of a series of directory names separated by a platform dependent delimiter character. The delimiter character is ':' on Unix and Mac OS X, ';' on Windows. The returned string points into static storage; the caller should not modify its value. The list sys.path is initialized with this value on interpreter startup; it can be (and usually is) modified later to change the search path for loading modules.

PySys_SetPath(char *path):
Set sys.path to a list object of paths found in path which should be a list of paths separated with the platform’s search path delimiter (: on Unix, ; on Windows).
Hast du Idee, welche andere Funktionen soll ich dazu verwenden?


Nachdem ich den Suchpfad richtig gesetzt habe, kann ich mit dem Befehl PyRun_SimpleString("from pythontest import type") das Modul type importieren oder muss ich doch mit PyImport_Import() das erledigen? Kann ich eigentlich nach der Initialisierung( Py_Initialize() ) von Python alle Python Befehle in PyRun_SimpleString() einpacken und ausführen lassen?
BlackJack

@monternet: `Py_GetPath()` und `PySys_SetPath()` sind nicht das was ich beschrieben hatte. Eigentlich habe ich es doch relativ deutlich beschrieben: Du brauchst eine Funktion um ein Modul zu importieren (`sys`), dann eine Funktion um von einem Objekt, nämlich dem Modulobjekt, ein Attribut (`path`) abzufragen und dann eine um der Liste, die man da bekommt, entweder ein Element anzuhängen, oder es vorne einzufügen. Bei letzterem weiss ich jetzt gar nicht mal, ob es dafür eine C-Funktion gibt, oder ob man da nicht eventuell sich auch wieder das passende Attribute von der Liste holen muss (die `insert()`-Methode). Eventuell muss man noch schauen ob man eine C-Zeichenkette in ein Python-Objekt umwandeln muss. Das sind nicht zwei oder drei Zeilen C sondern schon ein paar mehr, insbesondere wenn man sich ordentlich um Fehlerbehandlung kümmern will.

Selbst wenn das mit den Funktionen zum setzen des Pfades funktionieren sollte, entspricht mein Weg mehr dem was man in Python schreiben würde und ist unabhängiger von der Plattform. Aber wenn Dir die beiden Funktionen einfacher erscheinen, kannst Du es ja erst einmal damit probieren.

Ob Du den Import mit `PyRun_SimpleString()` oder `PyImport_Import()` machst, hängt davon ab wo Du das Modul haben willst. Soll es in Python unter dem Namen `type` zur Verfügung stehen, musst Du es in Python schreiben und ausführen. Soll es in C zur Verfügung stehen, dann musst Du es in C importieren. Du kannst es natürlich auch in C importieren und zusätzlich das `__main__`-Modul und es dann dort als Attribut setzen.

`type` ist übrigens kein guter Name, denn es gibt ja schon eine gleichnamige Funktion, die man damit verdecken würde, und die bei der Fehlersuche sehr praktisch sein kann.
monternet
User
Beiträge: 15
Registriert: Donnerstag 15. September 2011, 09:14

Hi BlackJack,

ich habe mit PyRun_SimpleString() einige Python Befehle von Python Interpreter ausführen gelassen, nämlich folgende:

Code: Alles auswählen

import sys
sys.path.append('c:\mat\pyhontest')
import aab
das funktioniert. Hier ist aab ein Package. Ich möchte eigentlich ein Modul 'neutest' importieren. Dann habe ich den Befehl

Code: Alles auswählen

from aab import neutest
probiert. Das funktioniert nicht. Aber, der Befehl

Code: Alles auswählen

from time import time,ctime
funktioniert.

Kannst du mir sagen warum?


Vielen Dank!
BlackJack

@monternet: Was heisst „funktioniert nicht“ denn genau? Gibt es eine Ausnahme? Wenn ja welche? Und hast Du im zweiten Beispiel auch das ``sys.path.append('c:\mat\pyhontest')`` vorher gemacht? Ist `aab` auch wirklich ain Package? `__init__.py` ist vorhanden?

Mit '\' in Zeichenketten musst Du vorsichtig sein. Ich würde sicherheitshalber entweder alle escapen, oder ein „Raw“-Zeichenkettenliteral verwenden, oder einfach '/' nehmen.
monternet
User
Beiträge: 15
Registriert: Donnerstag 15. September 2011, 09:14

BlackJack hat geschrieben:Ist `aab` auch wirklich ain Package? `__init__.py` ist vorhanden?
Ja, aab ist ein Package. Seine `__init__.py`Datei ist vorhanden und hat folgenden Code:

Code: Alles auswählen

__all__ = ["neutest", ...]


Ich habe folgendes gemach:

1.

Code: Alles auswählen

import sys
sys.path.append('c:\\mat\\pythontest')
import aab
aab.__name__
Das funktioniert und zeigt den Name ist aab.

Aber wenn ich so mache:
2.

Code: Alles auswählen

import sys
sys.path.append('c:\\mat\\pythontest')
from aab import *
Das geht nicht. Fehlermeldung ist :exceptions.SyntaxError
BlackJack

@monternet: Wie sieht denn der genaue Quelltext und der genaue Fehler mit Traceback aus? Der Traceback gibt vielleicht einen Hinweis darauf wo der Compiler den Fehler vermutet beziehungsweise wo er dann definitiv gemerkt hat, dass mit dem Quelltext etwas nicht stimmt.

Am Quelltext habe ich zweifel, weil der Quelltextschnippsel unter 1. nichts ausgibt — da fehlt ein ``print`` würde ich sagen. Du solltest den hier nicht „nachtippen“ sondern besser 1:1 kopieren, denn sonst sucht man Fehler die beim abgeschriebenen vielleicht gar nicht mehr vorhanden sind.
monternet
User
Beiträge: 15
Registriert: Donnerstag 15. September 2011, 09:14

@BlackJack:

Danke für die Hinweise. Ich habe verziechtet, von Labview aus zu embedded Python einzugreifen, sondern direkt von einer Win32 Applikation aus mit embedded Python zu testen. Deshalb kann ich nun vollständige Traceback bekommen.

Was mir nun aufgefallen ist folendes:

1. embedded Python kann das Verzeichniss aab selbst finden ohne ich der zusätzliche Pfad hinzufügen zu müssen.

2. Um neutest zu initialisieren werden mehrere Module initialisiert. Dazu kommt ein ImportError:
import win32api
ImportError: DLL load failed: Eine DLL-Initialisierungsroutine ist fehlgeschlagen.


Hast du Idee dazu?


Vielen Dank im Vorraus!
Antworten