gpt4 book ai didi

python - PyTuple_SetItem 的限制

转载 作者:太空狗 更新时间:2023-10-29 18:29:57 30 4
gpt4 key购买 nike

我有一个 Python 扩展模块,它创建一个元组作为另一个对象的属性,并在元组中设置项目。每当我在 Python 中执行此模块时,我都会收到错误 SystemError: bad argument to internal function

在阅读了 PyTuple 的文档并调试了我的程序几个小时后,我仍然无法弄清楚到底发生了什么。通过调试器运行我的程序表明问题发生在 Python 解释器内的库调用中。所以,最后,我看了下Python源码,终于明白了问题所在。 PyTuple_SetItem 函数有一个有趣的限制,我不知道,也找不到明确的记录。

这是 Python 源代码中的重要函数(为清楚起见进行了编辑):

int PyTuple_SetItem(register PyObject *op, register Py_ssize_t i, PyObject *newitem)
{
.....
if (!PyTuple_Check(op) || op->ob_refcnt != 1) {
Py_XDECREF(newitem);
PyErr_BadInternalCall();
return -1;
}
.....
}

这里重要的一行是条件 op->ob_refcnt != 1。所以这就是问题所在:你甚至不能调用 PyTuple_SetItem 除非 Tuple 的引用计数为 1。看起来这里的想法是你永远不应该使用 PyTuple_SetItem 除了在使用 PyTuple_New() 创建元组之后。我想这是有道理的,因为毕竟元组应该是不可变的,所以这个限制有助于使您的 C 代码更符合 Python 类型系统的抽象。

但是,我找不到任何地方记录此限制。相关文档似乎是 herehere ,两者均未指定此限制。文档基本上说当您调用 PyTuple_New(X) 时,元组中的所有项目都被初始化为 NULL。由于 NULL 不是有效的 Python 值,因此扩展模块程序员需要确保在将元组返回给解释器之前用正确的 Python 值填充元组中的所有槽。但它没有在任何地方说明必须在 Tuple 对象的引用计数为 1 时执行此操作。

所以现在,问题是我基本上把自己写进了一个角落,因为我不知道 PyTuple_SetItem 的这个(未记录?)限制。我的代码的结构使得在元组本身成为另一个对象的属性之后之前将项插入元组非常不方便。因此,当需要填充元组中的项目时,元组已经具有更高的引用计数。

我可能不得不重组我的代码,但我认真考虑过暂时将 Tuple 的引用计数设置为 1,插入项,然后恢复原始引用计数。当然,我知道这是一个可怕的黑客攻击,而不是任何一种永久性的解决方案。无论如何,我想知道有关元组引用计数的要求是否在任何地方记录。它只是 CPython 的一个实现细节,还是 API 用户可以依赖的预期行为?

最佳答案

我很确定您可以使用 PyTuple_SET_ITEM 而不是 PyTuple_SetItem 来绕过这些限制。 PyTuple_SET_ITEM是在tupleobject.h中定义的一个宏,如下:

#define PyTuple_SET_ITEM(op, i, v) (((PyTupleObject*)(op))->ob_item[i] = v

因此,如果您绝对、肯定且完全确定:

  1. op 是元组对象
  2. 到目前为止你还没有初始化元组中的槽 i
  3. 您拥有对 v 的引用并且您想让元组窃取它并且
  4. 在您调用 PyTuple_SET_ITEM
  5. 之前,另一个 Python 对象不可能使用该元组做任何事

那么我猜你可以安全地使用 PyTuple_SET_ITEM

关于python - PyTuple_SetItem 的限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6111843/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com