如何在内部存储和映射变量名称?

How are variables names stored and mapped internally?

我读过 并且在 CPython 中,变量似乎只是与引用关联的名称。

There are several things going on with the statement x=5:

  1. an int object with the value of 5 is created (or found if it already exists)
  2. the name x is created (or disassociated with the last object 'x' labeled)
  3. the reference count to the new (or found) int object is increased by 1
  4. the name x is associated with the object with the value '5' created (or found).

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

即:

  1. the name x is created (or disassociated with the last object 'x' labeled);

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

  1. the name x is associated with the object with the value '5' created (or found)

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

I think at a high level it can be done with a dict, where the key is the variable name (str?) and the value is the reference that it's associated with.

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

当你写x = 5时,名称x被设置为全局名称字典中的一个关键字,5作为对应的值。您可以 return 并使用 globals() 函数检查此字典,该函数给出当前作用域名称 space.

的内容

因此您也正确地认为名称 x 占用了 space。它作为字符串存在于内存中的某处,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 opcode used. This opcode functions in the same way (see here 的简短描述。