【问题标题】:Python reference count and ctypesPython 引用计数和 ctypes
【发布时间】:2010-10-14 08:50:33
【问题描述】:

你好,

我在理解 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 函数本身就是一个 ref)。

现在我不能在 C++ 中返回之前创建Py_DECREF(),因为对象被删除了。我可以减少python中的引用计数吗?

编辑 调用 cast 函数时,引用计数会发生什么变化?从下面的文档中我不太确定。 http://docs.python.org/library/ctypes.html#ctypes.cast

ctypes.cast(obj, 类型) 此函数类似于 C 中的强制转换运算符。它返回一个新的类型实例,该实例指向与 obj 相同的内存块。 type 必须是指针类型,obj 必须是可以解释为指针的对象。

【问题讨论】:

    标签: python c ctypes reference-counting


    【解决方案1】:

    在进一步的研究中,我发现可以指定函数的返回类型。 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
    

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

    【讨论】:

      【解决方案2】:

      您的 c++ 代码似乎是使用 official C-API 的经典包装器,这有点奇怪,因为 ctypes 通常用于在 python 中使用经典 c 类型(如 int、float 等......)。

      我个人“单独”使用 C-API(没有 ctypes),但根据我的个人经验,在这种情况下您不必担心引用计数器,因为您返回的是带有 Py_BuildValue 的本机 python 类型。当一个函数返回一个对象时,返回对象的所有权被赋予调用函数。

      只有当您想更改对象的所有权时,您才需要担心 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中borrowed and owned reference的概念。这对于正确理解引用计数器至关重要。

      【讨论】:

      • 但是你创建了一个python-c模块对吧?我想跳过它,使用 ctypes 你可以ctypes.cdll.LoadLibrary('some.so')。所以返回类型处理是不同的。对于 ctypes,它是 ctypes.py_object。然后我使用 cast 函数,但我不确定如何正确处理引用计数。查看我的编辑。
      • 是的,确实,这可能有点复杂......我试图阅读 cast() 的代码源,但我没有足够的时间来正确调查。当我有足够的时间时,我会尝试看看并编辑我的答案,如果我找到证明 ctypes 拥有所有权的东西(如果是这种情况,也许你应该考虑直接创建一个 python-c 对象来消除这些问题. 这很容易,因为您已经在使用 PyObject)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-24
      • 1970-01-01
      相关资源
      最近更新 更多