【问题标题】:C-Extension: Ref count of generatorsC-Extension:生成器的参考计数
【发布时间】:2019-12-16 17:06:13
【问题描述】:

我正在尝试为我的 c 扩展正确获取 Py_INCREFPy_DECREF。 在这样做的同时,我一直在为发电机的高价值而磕磕绊绊。我有什么 一直在做的是:

// Forgive me for leaving out the NULL checks
PyObject *get_generator = PyUnicode_InternFromString("get_generator");
PyObject *callback;
PyObject *seq;
PyObject *item;

callback = PyObject_CallMethodObjArgs(parent->state, get_generator, NULL);
seq = PyObject_GetIter(tmp);

Py_DECREF(callback);

while ((item = PyIter_Next(seq))) {
    ...
    Code
    ...
    Py_DECREF(item);
}
Py_DECREF(seq);
printf("!!!%zd\n", seq);

谁能解释一下。

【问题讨论】:

  • seq = PyObject_GetIter(tmp); - 你是说seq = PyObject_GetIter(callback);吗?
  • printf("!!!%zd\n", seq); 是什么?你认为这是在打印引用计数吗?这将打印指针值。无论如何,在那里打印引用计数可能是无效的,因为该对象很可能已被破坏
  • @DavidW 我的意思是seq = PyObject_GetIter(callback);printf("!!!%zd\n", seq); 是我的一个愚蠢的错误。我的意思是写seq->ob_refcnt

标签: python python-3.x python-c-api refcounting


【解决方案1】:

printf("!!!%zd\n", seq); 不是在打印引用计数,而是在打印原始指针地址(有点不正确,因为不能保证指针和带符号的size_t 可以兼容打印)。

还请注意,如果您没有持有自己拥有的指针(或已安全借用),则检查实际引用计数是不安全的,因此在 Py_DECREF 之后检查(当您放弃所有权时)是未定义的行为。

要修复,请更改:

Py_DECREF(seq);
printf("!!!%zd\n", seq);

到:

printf("!!!%zd\n", Py_REFCNT(seq));
Py_DECREF(seq);

在正常情况下,您应该期望看到计数为 1,但如果传递给 PyObject_GetIter 的对象本身就是一个迭代器(使 PyObject_GetIter 成为标识函数,除了增加引用计数并返回其他未修改的值之外什么都不做参数),那么如果其他地方可能存在对同一迭代器的其他引用,则计数可能会更高。

假设它们不是为了简洁而被省略,您确实需要添加对返回值的检查;如果引发异常,几乎所有 API 调用都可能返回 NULL,并且默默地继续处理而不是立即传递错误,可能会冒着用(无用的)段错误替换(有用的)异常消息/回溯的风险。

【讨论】:

  • Dooh...为我的愚蠢错误道歉。引用计数仍然很高,但在限制范围内。我还不明白为什么,但我可能会删除这个问题,因为它对 SO 没有任何价值。
  • 尽管我忘记了seq->ob_refcnt,而且我的问题一开始也有点愚蠢。你的回答其实很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-18
  • 2014-09-02
相关资源
最近更新 更多