STORE_NAME和STORE_GLOBAL在主作用域中等价吗?
我想我对Python中的模块命名空间有点困惑。我玩了一下Byteplay,试了以下操作:
我构建了一个与以下内容等价的操作码列表:(byteplay的printcodelist) ->
0 LOAD_CONST 3 1 STORE_NAME a 2 LOAD_CONST None 3 RETURN_VALUE
但是当我这样执行它时:
exec mycode in t #t is {} print 'a' in t #False , but I expected True
当我
时,情况也是一样。当我把import b 'a' in b.__dict__ #False b.a #error
替换成STORE_NAME
时,它就能正常工作。不过我以为STORE_NAME是用来在当前的本地命名空间中存储一个值的。但顶层的本地命名空间不就是全局命名空间吗?比如说STORE_GLOBAL
在主作用域中如果只用一次,那它是真的。locals() == globals()
基本上:如果我用内置的编译函数编译“a = 3”,
dis.dis() and bytecode's Code.from_code(codeobject) show STORE_NAME
。 嗯
1 个回答
3
我尝试按照你的步骤操作,结果一切都正常。我们来一步一步看看这个过程。首先是代码的创建。
在这里,我们导入所有需要的东西:
from byteplay import Code, LOAD_CONST, STORE_NAME, RETURN_VALUE
接下来,我们创建一个操作码列表,里面有合适的参数(这是一个元组的列表,每个元组的第一个元素是操作码,第二个元素是参数):
lst = [
(LOAD_CONST, 3),
(STORE_NAME, 'a'),
(LOAD_CONST, None),
(RETURN_VALUE, None)
]
好了,这部分完成了。接下来,最重要的一步是创建一个代码对象。它需要10个参数。我们来逐个看看:
x = Code(
lst, # opcodes list (what we execute)
[], # outer scope variables (obviously, we don't have any here),
[], # arguments (nothing here),
False, # *args here? Nope
False, # **kwargs here? Nope
False, # !!!Important!!! DO WE CREATE NEW NAMESPACE? No! We use given!
'', # name ...
'', # filename ... who cares...
0, # first line number
'' # docstring
)
注意! 如果创建代码时第六个参数设置为 True,那么在代码执行后,你将无法在局部变量中找到 'a' 这个变量。这是因为函数会创建自己的命名空间(co_names),而我们执行代码的命名空间不会包含 'a' 这个变量。
那么,我们来运行它吧!
nsloc = {} # locals to execute code with
nsglob = {} # globals to execute code with
# We could use one namespace for both but that doesn't matter
exec x.to_code() in nsglob, nsloc
print nsloc
结果和预期的一样:
{'a': 3}
希望这对你有帮助。