python - C-Extension:生成器的参考计数
问题描述
我正在尝试让我的 c 扩展名的Py_INCREF
's 和Py_DECREF
's 正确。在这样做的同时,我一直在为发电机的真正高价值而磕磕绊绊。我一直在做的事情如下:
// 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
标识函数,除了增加引用计数并返回未修改的参数之外什么都不做),那么计数可能会更高如果其他地方可能存在对同一迭代器的其他引用。
假设它们不是为了简洁而被省略,您确实需要添加对返回值的检查;NULL
如果引发异常,几乎所有 API 调用都可能返回,并且默默地继续处理而不是立即传递错误,可能会冒着用(无用的)段错误替换(有用的)异常消息/回溯的风险。
推荐阅读
- html - 网格中具有某些分辨率的图像在调整大小时会改变高度
- php - Laravel 的第二个 app.css 文件的目的是什么?
- javascript - 使用 selenium getHashCode() 函数比较页面上的两个元素,c#
- flutter - 如何根据上面的文字使按钮不移动?
- mongodb - 如何从 mongodb 聚合中的 2 个数组创建对象?
- html - 为什么 CSS 中的 :not 选择器在没有指定元素的情况下不能工作?
- c# - 如何将 Xamarin.Forms Xamarin.GooglePlayServices.Ads.Lite 从 v119.6 更新到 v119.7?
- javascript - 如何使用 JavaScript 在 Adobe Acrobat Pro DC 中删除基于关键字的 PDF 页面?
- elasticsearch - Vega-Lite + Kibana:将大小单位与 x 轴时间单位相匹配,以实现事件之间的准确时间跨度
- sql - sql sum over with where 条件