C-Extension:生成器的引用计数
C-Extension: Ref count of generators
我正在尝试为我的 c 扩展获取 Py_INCREF
和 Py_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);
谁能解释一下。
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
成为恒等函数,除了递增引用什么都不做count 和 returning 否则未修改的参数),那么如果其他地方可能存在对同一迭代器的其他引用,则计数可能更高。
假设它们不是简单地为了简洁而省略,您确实需要添加对 return 值的检查;如果引发异常,几乎所有 API 调用都可以 return NULL
,并且默默地继续处理而不是立即传递错误可能会替换(有用的)异常 message/traceback有一个(无用的)段错误。
我正在尝试为我的 c 扩展获取 Py_INCREF
和 Py_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);
谁能解释一下。
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
成为恒等函数,除了递增引用什么都不做count 和 returning 否则未修改的参数),那么如果其他地方可能存在对同一迭代器的其他引用,则计数可能更高。
假设它们不是简单地为了简洁而省略,您确实需要添加对 return 值的检查;如果引发异常,几乎所有 API 调用都可以 return NULL
,并且默默地继续处理而不是立即传递错误可能会替换(有用的)异常 message/traceback有一个(无用的)段错误。