我读了https://stackoverflow.com/a/19721096/1661745,似乎在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
?),值是它与之关联的引用。
答案 0 :(得分: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为值)。
Here是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
),您可能会看到使用的STORE_NAME
操作码。此操作码以相同的方式运行(有关简要说明,请参阅here。)