STORE_NAME和STORE_GLOBAL在主作用域中等价吗?

4 投票
1 回答
596 浏览
提问于 2025-04-17 08:04

我想我对Python中的模块命名空间有点困惑。我玩了一下Byteplay,试了以下操作:

  1. 我构建了一个与以下内容等价的操作码列表:(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_GLOBAL 
    时,它就能正常工作。不过我以为STORE_NAME是用来在当前的本地命名空间中存储一个值的。但顶层的本地命名空间不就是全局命名空间吗?比如说
    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}

希望这对你有帮助。

撰写回答