为什么python VM有co_names而不是只使用co_consts?

时间:2015-01-28 08:28:26

标签: python bytecode vm-implementation

Python编译器生成的代码对象包含指令中使用的常量元组(名为co_consts),还包含一个包含名称的元组(名为co_names)。

为什么要有两个不同的列表?仅仅使用co_consts作为名称也不会更简单吗?

2 个答案:

答案 0 :(得分:6)

考虑以下功能。

def f(x):
    x += n
    return x * 4

此处x是本地名称,其值可以更改。 4是一个常量。它的价值永远不会改变。但是,它仍然是一个对象,最好缓存它们,而不是每次需要时创建一个新对象。最后,n是全球参考。字符串"n"由函数存储,以便它可以用作从函数的全局上下文中检索n的键。

>>> f.__code__.co_nlocals # just 1 (for x)
1
>>> f.__code__.co_consts
(None, 4)
>>> f.__code__.co_names
('n',)
>>> "n" in f.__globals__ and globals() is f.__globals__
True

保持名称和内容分离的原因是为了内省。合并元组的唯一真正原因是内存效率,尽管这只会获得一个对象和每个函数一个指针。请考虑以下功能。

def g():
    return "s" * n

如果包含consts的元组与包含名称的元组合并,那么你(不是VM)将无法分辨哪些值用于访问全局变量以及哪些是函数的常量。

答案 1 :(得分:1)

我知道这个答案就像是过时了11个月,但是从我的修修补补来看似乎发生了以下情况

要访问字节码中的co_names,可以使用LOAD_GLOBAL(co name index),这会将对所需co_names的引用推送到堆栈上,例如其间接

要访问字节码中的co_consts,可以使用LOAD_CONST(co consts index),这会将存储在所需co_consts中的实际值推送到堆栈上,例如直接

我不确定它在python级别有任何直接影响,但在字节码级别它有很大差异