1

我正在用 C 编写一个 python 模块,我需要让它调用一个 Python 函数,其中一个参数由“引用”传递。最终结果应该是 Python 函数对参数所做的事情被保存到原始 C 变量中。

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

为了测试,我让 tcpResumeFunc 表示的 Python 函数将传入的整数修改为 = 5。但是,当我在这段代码的末尾打印出 *resume 时,它​​保留了它的初始值 -1。我知道我误解了 API 的工作原理。有什么建议么?

4

1 回答 1

4

我认为您对变量在 Python 中的工作方式存在误解。Python 中的变量不包含值;它们指的是它们 - 就像在 Java 中一样,除了没有“原语”(甚至没有int)。对变量的赋值不会覆盖旧值;它只是导致变量引用新值并停止引用旧值(如果没有其他引用它,则可能会被垃圾收集)。

为什么不直接返回(并使用)一个值(因为 Python 函数总是返回一些东西,即使它只是 的隐式返回None)?


编辑:通过一个例子工作,因为评论回复太长了。

在 C 中,我们调用 PyObject_CallFunction,它将 PyObject* 交给 Python 函数。在 Python 中,函数参数(我们称之为spam)现在指的是指向的 PyObject。

当我们在函数中写入spam += 6时,与spam = spam + 6. 字节码解释器获取表示值 6 的 PyObject,运行一个特殊的字节码来检查两个对象表示的值,添加它们,然后创建一个表示总和的新 PyObject(或从缓存中获取一个)。

然后spam是反弹到新对象;但是spam变量引用位于内存栅栏的 Python 端,与栅栏 C 端的 PyObject* 不同。

因此,resumeInt不会指向新创建/获取的 PyObject

它实际上的行为方式与从 Python 调用 Python 函数的方式完全相同。尝试一下:

def fry(spam):
  spam += 1

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

发生这种情况是因为重新绑定spam不影响eggs,这是一个单独的变量。我们不是通过引用传递;我们通过 value传递引用。就像在 Java 中一样。

于 2010-12-03T04:56:33.477 回答