问题描述
我阅读了 ,似乎在 CPython 中,变量只是与引用关联的名称。
语句 x=5 有几件事情发生:
- 一个值为 5 的 int 对象被创建(或者如果它已经存在则找到)
- 名称 x 被创建(或与最后一个标记为“x”的对象解除关联)
- 对新(或找到)int 对象的引用计数增加 1
- 名称 x 与创建(或找到)值为“5”的对象相关联。
但是,我仍然不清楚变量是如何在内部实现的。
即:
- 名称 x 被创建(或与最后一个标记为“x”的对象解除关联);
那名字不会也占用内存空间吗?
sys.sizeof(x)
等于sys.sizeof(5)
,我知道sys.sizeof(x)
只能返回关联引用的大小,但是名称x
的大小是多少?
- 名称 x 与创建(或找到)值为“5”的对象相关联
这是如何在内部实施的?
我认为在高层次上它可以用dict
来完成,其中键是变量名( str
?),值是与之关联的引用。
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)。
是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();
}
您可以看到调用PyDict_SetItem
以更新全局字典。
* 如果您检查x = 5
生成的字节码(例如使用dis
),您可能会看到使用的操作码。
此操作码的功能相同(请参阅 的简要说明)。