您可以使用以下命令查看每个Python版本生成的字节码:
>>> from dis import dis
并且,对于每个口译员:
#Python 3.2
>>> dis(Testing.__init__)
...
5 10 LOAD_GLOBAL 1 (a_func)
...
#Python 2.7
>>> dis(Testing.__init__)
...
5 8 LOAD_NAME 0 (a_func)
...
如您所见,Python 3.2搜索名为的全局值(LOAD_GLOBAL),a_func
而2.7首先搜索本地范围(LOAD_NAME),然后再搜索全局值。
如果在print(locals())
之后执行操作exec
,则会看到a_func
在__init__
函数内部创建了该代码。
我真的不知道为什么要这样做,但是似乎是对符号表处理方式的改变。
顺便说一句,如果想a_func = None
在您的__init__
方法之上创建一个使解释器知道它是局部变量的方法,则它将不起作用,因为字节码现在将是LOAD_FAST
而且不会进行搜索,而是直接从列表中获取值。
我看到的唯一解决方案是将globals()
作为第二个参数添加到exec
,这样将创建a_func
一个全局函数,LOAD_GLOBAL
操作码可以访问它。
如果删除该exec
语句,Python2.7会将字节码从更改LOAD_NAME
为LOAD_GLOBAL
。因此,使用exec
,您的代码在Python2.x上始终会变慢,因为它必须在本地范围内搜索更改。
由于python3exec
不是关键字,因此解释器无法确定它是否确实在执行新代码或执行其他操作……因此字节码不会改变。
例如
>>> exec = len
>>> exec([1,2,3])
3