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

one*_*ece 11 python variables cpython python-internals

我阅读/sf/answers/1380476751/,似乎在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'的对象相关联

这是如何在内部实施的?我认为在高级别它可以用a完成dict,其中键是变量名(str?),值是与之关联的引用.

Ale*_*ley 8

我认为在高级别它可以用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).

以下STORE_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();
}
Run Code Online (Sandbox Code Playgroud)

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


*如果检查由x = 5(例如使用dis)生成的字节码,您可能会看到使用的STORE_NAME操作码.该操作码以相同的方式起作用(参见此处的简要说明).