Ich möchte also einen Python-Code von c über cython aufrufen. Ich habe es geschafft, Cython-Code von c aufzurufen. Und ich kann auch Python-Code von Cython aufrufen. Aber wenn ich alles zusammenzähle, fehlen einige Dinge.
Hier ist mein Python-Code (quacker.pyx):
def quack():
print "Quack!"
Hier ist meine Cython “Brücke” (caller.pyx):
from quacker import quack
cdef public void call_quack():
quack()
Wenn ich das ausführe, bekomme ich diese Ausnahme:
Exception NameError: "name 'quack' is not defined" in 'caller.call_quack' ignored
Die fehlenden Teile, die ich vermute:
Ich habe nicht angerufen initquacker()
Ich habe nicht eingeschlossen quacker.h
Cython hat keine produziert quacker.h – only quacker.c
caller.c importiert nicht quacker.h oder anrufen initquacker()
Ich bin mir nicht wirklich sicher, ob es überhaupt möglich ist, das zu tun, was ich versuche, aber es scheint mir, dass es so sein sollte. Ich würde gerne jede Eingabe hören, die Sie haben könnten.
Bearbeiten:
So cythonisiere / kompiliere / verlinke / führe ich aus:
$ cython *.pyx
$ cc -c *.c -I/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7
$ cc -L/System/Library/Frameworks/Python.framework/Versions/2.7/lib -L/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config -lpython2.7 -ldl *.o -o main
$ ./main
Kann die Quacker-Datei einfach eine Python-.py-Datei sein, oder muss es eine .pyx-Datei sein?
– brm
23. März 2014 um 13:29 Uhr
Kannst du posten, wie du das alles zusammengestellt hast?
– hivert
23. März 2014 um 14:36 Uhr
@brm Ja, das würde ich sogar bevorzugen, da sich der gesamte Python-Code, auf den ich zugreifen möchte, bereits in .py-Dateien befindet.
– Pius
23. März 2014 um 15:51 Uhr
@hivert Ich habe mein hausgemachtes Build-Skript in einer Bearbeitung hinzugefügt
– Pius
23. März 2014 um 15:52 Uhr
brm
Wenn Sie die umbenennen quacker.pyx zu quacker.py, ist eigentlich alles richtig. Das einzige Problem ist, dass Ihr Programm im aktuellen Verzeichnis nicht nach Python-Modulen sucht, was zu folgender Ausgabe führt:
Exception NameError: "name 'quack' is not defined" in 'caller.call_quack' ignored
Wenn Sie jedoch das aktuelle Verzeichnis zur Umgebungsvariablen PYTHONPATH hinzufügen, wird die Ausgabe wie erwartet aussehen:
$ PYTHONPATH=".:$PYTHONPATH" ./main
Quack!
Beim Ausführen der Python-Shell gemäß der Dokumentation das aktuelle Verzeichnis (oder das Verzeichnis, das das Skript enthält) wird hinzugefügt sys.path Variable automatisch, aber beim Erstellen eines einfachen Programms mit Py_Initialize und Py_Finalize das scheint nicht zu passieren. Da die Variable PYTHONPATH auch zum Auffüllen der sys.path python-Variable erzeugt die obige Problemumgehung das richtige Ergebnis.
Alternativ unterhalb der Py_Intialize Zeile, könnten Sie eine leere Zeichenfolge hinzufügen sys.path wie folgt, indem Sie einfach einen Python-Code ausführen, der als Zeichenfolge angegeben ist:
Nach dem Neukompilieren läuft es einfach ./main sollte dann funktionieren.
Bearbeiten
Es ist tatsächlich interessant zu sehen, was passiert, wenn Sie den Code wie in der Frage angegeben ausführen, also ohne Umbenennung der quacker.pyx Datei. In diesem Fall ist die initcaller() Funktion versucht, die zu importieren quacker Modul, aber da nein quacker.py oder quacker.pyc vorhanden ist, das Modul nicht gefunden werden kann und die initcaller() Funktion erzeugt einen Fehler.
Jetzt wird dieser Fehler auf Python-Weise gemeldet, indem eine Ausnahme ausgelöst wird. Aber der Code in der main.c Datei prüft dies nicht. Ich bin kein Experte darin, aber in meinen Tests füge ich den folgenden Code hinzu initcaller() schien zu funktionieren:
if (PyErr_Occurred())
{
PyErr_Print();
return -1;
}
Die Ausgabe des Programms sieht dann wie folgt aus:
Traceback (most recent call last):
File "caller.pyx", line 1, in init caller (caller.c:836)
from quacker import quack
ImportError: No module named quacker
Durch den Aufruf der initquacker() Funktion Vorinitcaller()der Modulname quacker schon wird also der importaufruf eingetragen, das ist drinnen erledigt initcaller() erkennt, dass es bereits geladen ist, und der Aufruf wird erfolgreich sein.
Alternativ können Sie die einstellen PYTHONPATH mit PySys_SetPath("..."); wo … ist das, was Sie wollen.
– hivert
23. März 2014 um 17:07 Uhr
@hivert Wenn Sie das nur tun würden, würde sys.path nur auf ‘.’ gesetzt, also vermute ich, dass es schwierig wäre, andere Standardmodule zu finden
– brm
23. März 2014 um 17:10 Uhr
Gute Antwort :-). Ich denke, ich ziehe es vor, die zu setzen sys.path.insert Rufen Sie oben an caller.pyx. Und das PyErr_Occurred Trick funktioniert super.
– Pius
23. März 2014 um 20:19 Uhr
Falls sich jemand fragt, wie es in Python 3 funktionieren würde, hier ist meine Lösung, nachdem ich als Cython-Neuling ein wenig gekämpft habe.
Schön, das geht :-). Es ist allerdings etwas hackig. Um diese Methode zu verwenden, muss ich falsche Attribute in alle meine Python-Dateien einfügen. Es bedeutet auch, dass mein C-Code alle meine Python-Module kennen muss. Ich würde es vorziehen, dass der C-Code nur die Bridge (caller.pyx) kennt.
– Pius
23. März 2014 um 16:06 Uhr
Sie brauchen diese Header-Datei eigentlich nicht. In C können Funktionen implizit deklariert werden, sodass der Code auch ohne Header-Datei funktioniert, indem man einfach initquacker() aufruft
– brm
23. März 2014 um 16:38 Uhr
Das stimmt! Ich habe eigentlich nur aufgegeben, nachdem der Compiler mir diese Warnung gegeben hat: main.c:7:3: warning: implicit declaration of function 'initquacker' is invalid in C99 [-Wimplicit-function-declaration]
– Pius
23. März 2014 um 20:02 Uhr
Ich musste dies mit CMake tun und habe dieses Beispiel schließlich neu erstellt. Sie finden das Repository mit einem vollständigen Arbeitsbeispiel hier.
Sie können das Beispiel entweder mit Docker auf der CLI oder mit Visual Studio erstellen und ausführen Entwicklungscontainer.
13345500cookie-checkRufen Sie den Python-Code von c über cython aufyes
Kann die Quacker-Datei einfach eine Python-.py-Datei sein, oder muss es eine .pyx-Datei sein?
– brm
23. März 2014 um 13:29 Uhr
Kannst du posten, wie du das alles zusammengestellt hast?
– hivert
23. März 2014 um 14:36 Uhr
@brm Ja, das würde ich sogar bevorzugen, da sich der gesamte Python-Code, auf den ich zugreifen möchte, bereits in .py-Dateien befindet.
– Pius
23. März 2014 um 15:51 Uhr
@hivert Ich habe mein hausgemachtes Build-Skript in einer Bearbeitung hinzugefügt
– Pius
23. März 2014 um 15:52 Uhr