PyDict_SetItem是否增加键的引用计数,如果是,则在代码中的何处发生?

马修·莫森(Matthew Moisen)

TLDR:PyDict_SetItem增加键和值,但是这在代码中的什么地方发生?

PyDict_SetItem调用insertdict

insertdict立即Py_INCREF对键和值执行操作。但是,在成功路径末尾,它将Py_DECREF在键上执行a (但不执行值)。在执行此操作之前,该代码中一定有一部分是我所缺少的,它PY_INCREF在键上做了额外的工作PY_DECREF我的问题是,此额外的PY_INCREF在何处发生,为什么会发生?为什么最初Py_INCREF的开头insertdict不足?

由此看来,乍看之下PyDict_SetItem只会增加值的引用计数,而不会增加键。当然,这不是真的。例如,在PyDict_SetItemString中,使用a char *,将其通过转换为PyObject PyUnicode_FromString(返回一个新值),并Py_DECREF在调用后对该新值执行a PyDict_SetItem如果PyDict_SetItem不增加密钥,PyDict_SetItemString而是减少刚刚创建的密钥,则该程序最终可能会出现段错误。鉴于这种情况不会发生,似乎我在这里丢失了一些东西。


最后,此代码应证明可以同时PyDict_SetItem增加键和值,并且调用者应同时取消键和值,除非借用了它们的引用/或将键和值提供给其他人。

#include <Python.h>
#include <stdio.h>

int main(void)
{
    Py_Initialize();
    PyObject *dict = NULL, *key = NULL, *value = NULL;
    int i = 5000;
    char *o = "foo";

    if (!(dict = PyDict_New())) {
        goto error;
    }
    if (!(key = Py_BuildValue("i", i))) {
        goto error;
    }
    if (!(value = Py_BuildValue("s", o))) {
        goto error;
    }
    printf("Before PyDict_SetItem\n");
    printf("key is %i\n", key->ob_refcnt);  /* Prints 1 */
    printf("value is %i\n", value->ob_refcnt);  /* Prints 1 */

    printf("Calling PyDict_SetItem\n");
    if (PyDict_SetItem(dict, key, value) < 0) {
        goto error;
    }
    printf("key is %i\n", key->ob_refcnt);  /* Prints 2 */
    printf("value is %i\n", value->ob_refcnt);  /* Prints 2 */

    printf("Decrefing key and value\n");
    Py_DECREF(key);
    Py_DECREF(value);
    printf("key is %i\n", key->ob_refcnt);   /* Prints 1 */
    printf("value is %i\n", value->ob_refcnt);   /* Prints 1 */

    Py_Finalize();
    return 0; // would return the dict in normal code
error:
    printf("error");
    Py_XDECREF(dict);
    Py_XDECREF(key);
    Py_XDECREF(value);
    Py_Finalize();
    return 1;
}

您可以像这样编译:

gcc -c -I/path/to/python/include/python3.7m dict.c
gcc dict.o -L/path/to/python/lib/python3.7/config-3.7m-i386-linux-gnu -L/path/to/python/lib -Wl,-rpath=/path/to/python/lib -lpython3.7m -lpthread -lm -ldl -lutil -lrt -Xlinker -export-dynamic -m32
user2357112支持Monica

Py_DECREF(key);insertdict不会发生的所有成就。如果已经存在一个相等的密钥,这成功发生的原因,要么是因为存在一个现有条目,要么是因为该dict是一个拆分表dict,它与拥有该密钥的其他dict共享密钥。在该路径上,没有插入提供的密钥,因此Py_INCREF(key);需要取消原始密钥

在不存在键的路径上,insertdict命中一条不同的return语句,并且不对键进行解引用:

if (ix == DKIX_EMPTY) {
    /* Insert into new slot. */
    assert(old_value == NULL);
    if (mp->ma_keys->dk_usable <= 0) {
        /* Need to resize. */
        if (insertion_resize(mp) < 0)
            goto Fail;
    }
    Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
    ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
    dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
    ep->me_key = key;
    ep->me_hash = hash;
    if (mp->ma_values) {
        assert (mp->ma_values[mp->ma_keys->dk_nentries] == NULL);
        mp->ma_values[mp->ma_keys->dk_nentries] = value;
    }
    else {
        ep->me_value = value;
    }
    mp->ma_used++;
    mp->ma_version_tag = DICT_NEXT_VERSION();
    mp->ma_keys->dk_usable--;
    mp->ma_keys->dk_nentries++;
    assert(mp->ma_keys->dk_usable >= 0);
    ASSERT_CONSISTENT(mp);
    return 0;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Python C API-PyDict-值和键是否需要引用计数?

来自分类Dev

shared_ptr:在基类的shared_ptr中复制时,引用计数是否增加?

来自分类Dev

shared_ptr:在基类的shared_ptr中复制时,引用计数是否增加?

来自分类Dev

乘飞机的乘客是否使用分叉,如果是,则在何处设置after_fork配置?

来自分类Dev

无法引用计数发生次数的列

来自分类Dev

当保持数组的引用计数增加时,如何增加子数组的引用计数?

来自分类Dev

当保持数组的引用计数增加时,如何增加子数组的引用计数?

来自分类Dev

类型的Memoryview是否会增加numpy.array的引用计数?

来自分类Dev

是否总是需要增加Py_True / Py_False引用计数?

来自分类Dev

将DLL固定在内存中(增加引用计数)

来自分类Dev

了解如何增加共享指针的强引用计数?

来自分类Dev

如果是整数则在数组中添加值

来自分类Dev

使用Delphi的引用计数功能时发生内存泄漏

来自分类Dev

rs.EOF = True是否可行?如果是,则在vb6.0中可以在哪种情况下使用?

来自分类Dev

检查单元格是否在范围内,如果是,则在 Excel VBA 中返回单词“Marginal”

来自分类Dev

即使在单线程程序中,共享指针是否在引用计数中使用原子操作

来自分类Dev

如果是perl,则代码引用中的变量范围需要解释奇怪的行为

来自分类Dev

如果是PUT或DELETE请求,则在任何http请求上都会发生“连接重置”

来自分类Dev

检查 Object1 的键是否在 Object2 中,如果是,则比较值

来自分类Dev

如果使用MYSQL,则在单个字段中是否需要使用唯一键?

来自分类Dev

static_pointer_cast是否更新引用计数

来自分类Dev

如果是HTTP 400响应代码,则在调用Web服务后获得错误消息

来自分类Dev

Delphi 2010-PID是否存在?如果是,则在列表框中显示PID,否则从列表框中删除PID

来自分类Dev

jQuery检查父元素中是否包含特定文本,如果是,则在特定的预先存在的子元素之后添加子元素

来自分类Dev

Excel:检查列A是否具有特定值,如果是,则在该值所在的行中显示另一个单元格

来自分类Dev

PostgreSQL中的“引用计数”触发器

来自分类Dev

分配工具中的引用计数问题

来自分类Dev

如何根据引用计数列表中的重复值

来自分类Dev

Netty 4:包装缓冲区中的引用计数

Related 相关文章

  1. 1

    Python C API-PyDict-值和键是否需要引用计数?

  2. 2

    shared_ptr:在基类的shared_ptr中复制时,引用计数是否增加?

  3. 3

    shared_ptr:在基类的shared_ptr中复制时,引用计数是否增加?

  4. 4

    乘飞机的乘客是否使用分叉,如果是,则在何处设置after_fork配置?

  5. 5

    无法引用计数发生次数的列

  6. 6

    当保持数组的引用计数增加时,如何增加子数组的引用计数?

  7. 7

    当保持数组的引用计数增加时,如何增加子数组的引用计数?

  8. 8

    类型的Memoryview是否会增加numpy.array的引用计数?

  9. 9

    是否总是需要增加Py_True / Py_False引用计数?

  10. 10

    将DLL固定在内存中(增加引用计数)

  11. 11

    了解如何增加共享指针的强引用计数?

  12. 12

    如果是整数则在数组中添加值

  13. 13

    使用Delphi的引用计数功能时发生内存泄漏

  14. 14

    rs.EOF = True是否可行?如果是,则在vb6.0中可以在哪种情况下使用?

  15. 15

    检查单元格是否在范围内,如果是,则在 Excel VBA 中返回单词“Marginal”

  16. 16

    即使在单线程程序中,共享指针是否在引用计数中使用原子操作

  17. 17

    如果是perl,则代码引用中的变量范围需要解释奇怪的行为

  18. 18

    如果是PUT或DELETE请求,则在任何http请求上都会发生“连接重置”

  19. 19

    检查 Object1 的键是否在 Object2 中,如果是,则比较值

  20. 20

    如果使用MYSQL,则在单个字段中是否需要使用唯一键?

  21. 21

    static_pointer_cast是否更新引用计数

  22. 22

    如果是HTTP 400响应代码,则在调用Web服务后获得错误消息

  23. 23

    Delphi 2010-PID是否存在?如果是,则在列表框中显示PID,否则从列表框中删除PID

  24. 24

    jQuery检查父元素中是否包含特定文本,如果是,则在特定的预先存在的子元素之后添加子元素

  25. 25

    Excel:检查列A是否具有特定值,如果是,则在该值所在的行中显示另一个单元格

  26. 26

    PostgreSQL中的“引用计数”触发器

  27. 27

    分配工具中的引用计数问题

  28. 28

    如何根据引用计数列表中的重复值

  29. 29

    Netty 4:包装缓冲区中的引用计数

热门标签

归档