exec()字节码与任意本地?

ily*_* n. 3 python bytecode codeblocks python-3.x

例如,假设我想执行代码

    value += 5
Run Code Online (Sandbox Code Playgroud)

在我自己的命名空间内(所以结果基本上是mydict['value'] += 5).有一个函数exec(),但我必须在那里传递一个字符串:

    exec('value += 5', mydict) 
Run Code Online (Sandbox Code Playgroud)

并且将语句作为字符串传递似乎很奇怪(例如,它没有这样的颜色).可以这样做:

    def block():
        value += 5

    ???(block, mydict)
Run Code Online (Sandbox Code Playgroud)

?最后一行的明显候选人是exec(block.__code__, mydict),但没有运气:它提出UnboundLocalErrorvalue.我相信它基本上执行block(),而不是块内的代码,所以分配并不容易 - 这是正确的吗?

当然,另一种可能的解决方案是拆卸block.__code__......

仅供参考,因为这个帖子,我得到了这个问题.此外,这就是为什么有些人(我未定)要求新语法

    using mydict: 
        value += 5
Run Code Online (Sandbox Code Playgroud)

注意这不会引发错误,但也不会改变mydict:

    def block(value = 0):
        value += 5

    block(**mydict)
Run Code Online (Sandbox Code Playgroud)

Ale*_*lli 6

您可以传递字节码而不是字符串exec,只需要为此目的制作正确的字节码:

>>> bytecode = compile('value += 5', '<string>', 'exec')
>>> mydict = {'value': 23}
>>> exec(bytecode, mydict)
>>> mydict['value']
28
Run Code Online (Sandbox Code Playgroud)

具体来说,......:

>>> import dis
>>> dis.dis(bytecode)
  1           0 LOAD_NAME                0 (value)
              3 LOAD_CONST               0 (5)
              6 INPLACE_ADD         
              7 STORE_NAME               0 (value)
             10 LOAD_CONST               1 (None)
             13 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

加载和存储指令必须是_NAME说服,这compile使得它们如此,而......:

>>> def f(): value += 5
... 
>>> dis.dis(f.func_code)
  1           0 LOAD_FAST                0 (value)
              3 LOAD_CONST               1 (5)
              6 INPLACE_ADD         
              7 STORE_FAST               0 (value)
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

...函数中的代码已经过优化,可以使用_FAST版本,而这些代码不适用于传递给它的字典exec.如果您使用_FAST指令以某种方式使用字节码开始,则可以修改它以使用_NAME类型,例如使用字节码或类似方法.