2010-12-03 8 views
1

Ich schreibe ein Python-Modul in C und ich muss es rufen Sie eine Python-Funktion mit einem der Argumente von "Referenz" übergeben. Das Endergebnis sollte sein, dass das, was die Python-Funktion für das Argument tut, in der ursprünglichen C-Variablen gespeichert wird.Python C API: Rufen Sie eine Python-Funktion mit Argument (s) durch Referenz übergeben

int  *resume;  // this int is actually passed in to this body of code 
PyObject *resumeInt; // which was originally a C callback func for libnids, but 
PyObject *ret;   // I removed/rewrote most of this code for clarity 

resumeInt = Py_BuildValue("i",-1); 
ret = PyObject_CallFunction(tcpResumeFunc, "(O)", resumeInt);  

*resume = PyInt_AsLong(resumeInt); 
Py_DECREF(ret); 
Py_DECREF(resumeInt); 

Um zu testen, ich hatte die Python-Funktion, die tcpResumeFunc die übergebenen-in = 5.em ganze Zahl darstellt, ändern Wenn ich * Lebenslauf am Ende dieses Codes ausdrucken, aber es behält es anfänglichen Wert -1 . Ich weiß, dass ich etwas falsch verstehe, wie die API funktioniert. Irgendwelche Vorschläge?

Antwort

4

Ich glaube, Sie verstehen etwas falsch über die Funktionsweise von Variablen in Python. Variablen in Python enthalten keine Werte. sie beziehen sich auf sie - wie in Java, außer dass es keine "Primitiven" gibt (nicht einmal int). Die Zuweisung zu einer Variablen überschreibt nicht den alten Wert; Es bewirkt lediglich, dass sich die Variable auf den neuen Wert bezieht und nicht mehr auf den alten Wert verweist (was dann zu einer Müllsammlung führen kann, wenn sich nichts anderes darauf bezieht).

Warum nicht einfach tatsächlich einen Wert zurückgeben (und verwenden) (da Python-Funktionen immer etwas zurückgeben, auch wenn es nur die implizite Rückgabe von None ist)?


Edit: Durch ein Beispiel arbeiten, weil es zu lange für eine Kommentarantwort ist.

Von C rufen wir PyObject_CallFunction auf, die ein PyObject * an die Python-Funktion übergeben. In Python bezieht sich der Funktionsparameter (wir nennen ihn spam) jetzt auf das zugespitzte PyObject.

Wenn wir spam += 6 in die Funktion schreiben, ist das das gleiche wie spam = spam + 6. Der Bytecode-Interpreter ruft das PyObject ab, das den Wert 6 darstellt, führt einen speziellen Bytecode aus, der den von den beiden Objekten dargestellten Wert prüft, addiert und ein neues PyObject erstellt (oder eines aus einem Cache abruft), das die Summe darstellt.

Dann wird spam Rebound auf das neue Objekt; aber die spam Variablenreferenz befindet sich auf der Python-Seite des Speicherzauns und ist nicht dasselbe wie das PyObject * auf der C-Seite des Zauns.

So wird resumeInt tut nicht get auf die neu erstellte/abgerufene PyObject.

Es verhält sich tatsächlich genauso, wie es die Python-Funktion von Python aufrufen würde. Versuchen Sie es:

def fry(spam): 
    spam += 1 

eggs = 3 
fry(eggs) 
eggs # still 3! 

Dies, weil spam rebinding geschieht nicht eggs nicht beeinflusst, was eine separate Variable ist. Wir gehen nicht durch Verweis; Wir übergeben eine Referenz von Wert. Genau wie in Java.

+0

Ich verstehe das, (ich denke) ich nahm an, dass seit * resumeInt auf das gleiche Objekt verwiesen, nach der Übergabe an PyObject_CallFunction würde ich mit der neuen * resumeInt wie von der Python-Funktion genannt genannt geändert werden. Dann wandle ich es einfach zurück in eine C-Variable mit PyInt_AsLong. Stimmt etwas nicht mit dieser Idee? Ihr Vorschlag klingt etwas eleganter und einfacher, aber ich würde das gerne verstehen. –

+0

Ah, nach deiner Bearbeitung macht es mehr Sinn. Also was ich versuche zu tun, wäre wahrscheinlich unmöglich. Ich werde den Code ändern, damit er den Wert zurückgibt.Ich würde abstimmen, aber ich habe nicht genug Ansehen; gute Antwort, vielen Dank! –

Verwandte Themen