2014-01-29 50 views
5

在模块级别声明的函数永远不会有闭包,并通过LOAD_GLOBAL访问非局部变量。全局变量与解除引用变量的实现

声明的功能而不是在模块级别可能有闭包并通过LOAD_DEREF访问非本地变量,如果这些变量不是全局变量的话。所以基本上我们有三种存储和加载变量的方法:GLOBAL(全局),FAST(本地)和DEREF(非本地,封闭,覆盖)。

为什么GLOBAL?如果让所有函数都关闭,那么FASTDEREF就足够了吗?非局部变量和全局变量之间是否存在一些重要区别?这可能是由于性能问题,因为也许全局变量(如模块级定义的所有函数和类(包括它们的方法)加上内建函数)通常比非局部变量更常见?

回答

5

在编译期间枚举本地名称和封闭名称。在运行时,它们存储在C数组中并使用整数/索引访问。 LOAD_FASTLOAD_DEREF取一个C整数并执行C数组查找。

全局名称无法在编译时枚举,它们可以在运行期间通过任何代码在整个过程中添加和删除。这与对象属性类似 - 因为全局变量本质上是模块对象的属性。因此,它们存储在字典中,并且实现的访问方式与本地名称和封闭名称的访问方式截然不同。 LOAD_GLOBAL需要一个字符串(常量)并执行字典查找。

+0

然后我猜在编译期间的枚举过程中,编译器还会判断一个变量是否(可能)从一个封闭范围内访问,并且在这些情况下使用'STORE_DEREF'而不是'STORE_FAST'。这是正确的吗? – Hyperboreus

+0

@Hyperboreus是的,它只是搜索作业和非本地声明。 – delnan

+0

这是否也意味着我需要两次扫描来编译一个块(范围,帧,我不知道正确的术语)?我的意思是,我需要所有*封闭*块的信息以便在“STORE_FAST”和“STORE_DEREF”之间做出决定。同时,我需要关于所有*封闭*块的信息,以便在“LOAD_DEREF”和“LOAD_GLOBAL”之间做出决定。因此编译一个孩子取决于父母,反之亦然。还是我得到这个错误? – Hyperboreus