Python 引用计数和 ctypes

发布于 2024-09-27 13:55:38 字数 916 浏览 7 评论 0原文

你好,

我在理解 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。我认为它应该是 2getrefcount 函数本身就是一个引用)。

现在我无法在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

欢你一世 2024-10-04 13:55:38

经过进一步的研究,我发现可以指定函数的返回类型。
http://docs.python.org/library/ctypes.html#callback-functions
这使得强制转换变得过时,并且引用计数不再是问题。

clib = ctypes.cdll.LoadLibrary('some.so')
c_foo = clib.c_foo
c_foo.restype = ctypes.py_object

由于没有给出其他答案,我接受我的新解决方案作为答案。

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.

clib = ctypes.cdll.LoadLibrary('some.so')
c_foo = clib.c_foo
c_foo.restype = ctypes.py_object

As no additional answers were given I accept my new solution as the answer.

忘羡 2024-10-04 13:55:38

您的 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 = py_Map["key"]

但由于所有权已授予调用函数,因此当您删除 F 时,您将调用析构函数C++ 中的映射包含一个指向已释放对象的指针!

解决方案是在 [] 的包装器中用 c++ 编写:

...
PyObject* result; // My py_Foo object
Py_XINCREF(result); // transfer the ownership
return result;
}

您应该看看 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 than Py_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 :

F = py_Map["key"]

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 [] :

...
PyObject* result; // My py_Foo object
Py_XINCREF(result); // transfer the ownership
return result;
}

You should take a look at the notion of borrowed and owned reference in python. This is essential to understand properly the reference counter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文