Python 引用计数和 ctypes
你好,
我在理解 python 引用计数时遇到了一些麻烦。 我想要做的是使用 ctypes 模块将元组从 c++ 返回到 python。
C++:
PyObject* foo(...)
{
...
return Py_BuildValue("(s, s)", value1, value2);
}
Python:
pointer = c_foo(...) # c_foo loaded with ctypes
obj = cast(pointer, py_object).value
我不确定 obj 的引用计数,所以我尝试了 sys.getrefcount()
并得到3
。我认为它应该是 2
(getrefcount
函数本身就是一个引用)。
现在我无法在 C++ 中的 return 之前创建 Py_DECREF()
因为对象被删除了。我可以减少Python中的引用计数吗?
编辑 调用强制转换函数时,引用计数会发生什么变化?从下面的文档中我不太确定。 http://docs.python.org/library/ctypes.html#ctypes.cast
ctypes.cast(obj, 类型) 该函数类似于C中的强制转换运算符。它返回一个新的类型实例,该实例与obj指向相同的内存块。 type 必须是指针类型,obj 必须是可以解释为指针的对象。
Hallo,
I have some troubles understanding the python reference count.
What I want to do is return a tuple from c++ to python using the ctypes module.
C++:
PyObject* foo(...)
{
...
return Py_BuildValue("(s, s)", value1, value2);
}
Python:
pointer = c_foo(...) # c_foo loaded with ctypes
obj = cast(pointer, py_object).value
I'm was not sure about the ref count of obj, so I tried sys.getrefcount()
and got 3
. I think it should be 2
(the getrefcount
functions makes one ref itself).
Now I can't make Py_DECREF()
before the return in C++ because the object gets deleted. Can I decrease the ref count in python?
edit
What happens to the ref count when the cast function is called? I'm not really sure from the documentation below. http://docs.python.org/library/ctypes.html#ctypes.cast
ctypes.cast(obj, type)
This function is similar to the cast operator in C. It returns a new instance of type which points to the same memory block as obj. type must be a pointer type, and obj must be an object that can be interpreted as a pointer.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
经过进一步的研究,我发现可以指定函数的返回类型。
http://docs.python.org/library/ctypes.html#callback-functions
这使得强制转换变得过时,并且引用计数不再是问题。
由于没有给出其他答案,我接受我的新解决方案作为答案。
On further research I found out that one can specify the return type of the function.
http://docs.python.org/library/ctypes.html#callback-functions
This makes the cast obsolete and the ref count is no longer a problem.
As no additional answers were given I accept my new solution as the answer.
您的 c++ 代码似乎是使用 官方 C-API 的经典包装器,这有点奇怪因为 ctypes 通常用于在 python 中使用经典的 c 类型(如 int、float 等)。
我个人“单独”使用 C-API(没有 ctypes),但根据我的个人经验,在这种情况下您不必担心引用计数器,因为您将使用
Py_BuildValue
。当函数返回一个对象时,返回对象的所有权将赋予调用函数。仅当以下情况时,您才需要担心
Py_XINCREF
/Py_XDECREF
(优于Py_INCREF
/Py_DECREF
因为它接受 NULL 指针)您想要更改对象的所有权:例如,您已经在 python 中创建了映射的包装器(我们将其称为类型化对象 py_map)。该元素属于 c++ 类 Foo,并且您已经为它们创建了另一个 python 包装器(我们称之为 py_Foo)。如果您创建一个包装 [] 运算符的函数,您将在 python 中返回一个 py_Foo 对象:
但由于所有权已授予调用函数,因此当您删除
F
时,您将调用析构函数C++ 中的映射包含一个指向已释放对象的指针!解决方案是在 [] 的包装器中用 c++ 编写:
您应该看看 Python 中借用和拥有的引用。这对于正确理解参考计数器至关重要。
Your c++ code seems to be a classic wrapper using the official C-API and it's a bit weird since ctypes is usually used for using classic c types in python (like int, float, etc...).
I use personnally the C-API "alone" (without ctypes) but on my personnal experience, you don't have to worry about the reference counter in this case since you are returning a native python type with
Py_BuildValue
. When a function returns an object, the ownership of the returned object is given to the calling function.You have to worry about
Py_XINCREF
/Py_XDECREF
(better thanPy_INCREF
/Py_DECREF
because it accepts NULL pointers) only when you want to change ownership of the object :For example, you have created a wrapper of a map in python (let's call the typed object py_map). The element are of c++ class Foo and you have created an other python wrapper for them (let's call it py_Foo). If you create a function that wrap the [] operator, you are going to return a py_Foo object in python :
but since the ownership is given to the calling function, you will call the destructor when you delete
F
and the map in c++ contains a pointer to a deallocated objet !The solution is to write in c++ in the wrapper of [] :
You should take a look at the notion of borrowed and owned reference in python. This is essential to understand properly the reference counter.