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

时间:2015-10-24 15:02:58

标签: python variables cpython python-internals

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

  

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

     
      
  1. 创建一个值为5的int对象(如果已经创建,则找到它   存在)
  2.   
  3. 创建名称x(或与最后一个对象取消关联)   ' X'标记的)
  4.   
  5. 对新(或找到)的int对象的引用计数是   增加1
  6.   
  7. 名称x与对象关联   价值' 5'创建(或找到)。
  8.   

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

即:

  
      
  1. 创建名称x(或与最后一个对象' x'标记无关;)
  2.   

那么这个名字也不会占用内存空间吗? sys.sizeof(x)等于sys.sizeof(5),我认为sys.sizeof(x)只能返回相关引用的大小,但是x的大小是多少?

  
      
  1. 名称x与对象关联,值为' 5'创建(或找到)
  2.   

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

1 个答案:

答案 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为值)。

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。)