【问题标题】:How are variables names stored and mapped internally?变量名称如何在内部存储和映射?
【发布时间】:2015-10-24 15:02:57
【问题描述】:

我阅读了https://stackoverflow.com/a/19721096/1661745,似乎在 CPython 中,变量只是与引用相关联的名称。

语句 x=5 发生了几件事:

  1. 创建了一个值为 5 的 int 对象(或者如果它已经找到了 存在)
  2. 名称 x 已创建(或与最后一个对象解除关联 'x' 标记)
  3. 对新的(或找到的)int 对象的引用计数是 增加了 1
  4. 名称 x 与对象相关联 创建(或找到)值“5”。

但是,我仍然不清楚变量是如何在内部实现的。

即:

  1. 名称 x 已创建(或与最后一个标记的对象“x”解除关联);

那么名字不也占用内存空间吗? sys.sizeof(x) 等于 sys.sizeof(5),我知道 sys.sizeof(x) 只能返回关联引用的大小,但是名称 x 的大小是多少?

  1. 名称 x 与创建(或找到)值为“5”的对象相关联

这是如何在内部实现的?我认为在较高级别上可以使用 dict 来完成,其中键是变量名 (str?),值是与之关联的引用。

【问题讨论】:

标签: python variables cpython python-internals


【解决方案1】:

我认为在高层次上可以使用 dict 来完成,其中键是变量名 (str?),值是与之关联的引用。

这也是它在内部的工作方式。在 CPython 中,变量名和它们指向的对象通常存储在 Python 字典中;与编写 Python 代码时可以使用的数据结构完全相同。

当您编写x = 5 时,名称x 被设置为全局名称字典中的键,对应的值为5。您可以使用globals() 函数返回并检查此字典,该函数提供当前作用域命名空间的内容。

所以你说x 占用空间也是正确的。它作为字符串存在于内存中的某处,Python 为字典的键保留对它的引用。

如果您想深入了解 CPython 源代码以查看 x 被分配到值 5 的位置,您可以查看 ceval.c。写入x = 5 会触发LOAD_CONST 操作码(将整数5 放入堆栈)和STORE_GLOBAL 操作码*(将名称x 设置为字典中的键,值是5)。

HereSTORE_GLOBAL 操作码的代码:

TARGET(STORE_GLOBAL) {
    PyObject *name = GETITEM(names, oparg);
    PyObject *v = POP();
    int err;
    err = PyDict_SetItem(f->f_globals, name, v);
    Py_DECREF(v);
    if (err != 0)
        goto error;
    DISPATCH();
}

您可以看到对 PyDict_SetItem 的调用以更新全局字典。


* 如果您检查x = 5 生成的字节码(例如使用dis),您可能会看到使用了STORE_NAME 操作码。此操作码的功能相同(请参阅here 以获得简要说明)。

【讨论】:

猜你喜欢
  • 2021-05-08
  • 2011-05-12
  • 1970-01-01
  • 1970-01-01
  • 2017-09-07
  • 2016-07-07
  • 1970-01-01
  • 2013-08-27
  • 1970-01-01
相关资源
最近更新 更多