开发者

Python C API: Call a Python function with argument(s) passed by reference

开发者 https://www.devze.com 2023-01-28 11:47 出处:网络
I\'m writing a python module in C and I need to开发者_JAVA百科 have it call a Python function with one of the arguments passed by \"reference\".The end result should be that what the Python function d

I'm writing a python module in C and I need to开发者_JAVA百科 have it call a Python function with one of the arguments passed by "reference". The end result should be that what the Python function does to the argument gets saved into the original C variable.

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);

To test, I had the Python function that tcpResumeFunc represents modify the passed-in integer to = 5. When I print out *resume at the end of this code, however, it retains it's initial -1 value. I know I am misunderstanding something about how the API works. Any suggestions?


I think you're misunderstanding something about how variables work in Python. Variables in Python do not contain values; they refer to them - like in Java, except there are no "primitives" (not even int). Assignment to a variable doesn't overwrite the old value; it simply causes the variable to refer to the new value and cease referring to the old one (which may then be garbage-collected if nothing else refers to it).

Why not just actually return (and use) a value (since Python functions always return something anyway, even if it's just the implicit return of None)?


Edit: Working through an example, because it's too long for a comment reply.

From C, we call PyObject_CallFunction, which hands a PyObject* over to the Python function. In Python, the function parameter (we'll call it spam) now refers to the pointed-at PyObject.

When we write spam += 6 in the function, that is the same as spam = spam + 6. The bytecode interpreter gets the PyObject that represents the value 6, runs a special bytecode that inspects the value represented by the two objects, adds them, and creates a new PyObject (or fetches one from a cache) that represents the sum.

Then spam is rebound to the new object; but the spam variable-reference is on the Python side of the memory fence, and is not the same thing as the PyObject* on the C side of the fence.

Thus, resumeInt does not get pointed at the newly created/fetched PyObject.

It is actually behaving the exact same way as it would calling the Python function from Python. Try it:

def fry(spam):
  spam += 1

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

This happens because rebinding spam does not affect eggs, which is a separate variable. We are not passing by reference; we are passing a reference by value. Just like in Java.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号