头图

在前面《Python 代码动态执行初探》中讲到过如何用exec和eval函数动态执行代码,也描述了如何限制其命名空间,避免动态代码造成环境“污染”。

不过,有的时候,我们的确想要让动态代码生成一些局部或全局的定义——比如一个变量名——让原始代码或者后面的动态代码可以继续使用。像下面这样直接定义是无法生效的:

def f():
    a = 1
    exec("a = 3")
    print(a)

此时打印的结果会是1,也就是说exec中对a的修改被丢弃了。不过可以采用locals参数来取回修改:

def foo():
    ldict = {}
    exec("a=3",globals(),ldict)
    a = ldict['a']
    print(a)

这里的打印结果就是3了。

本文的示例代码取自stack overflow的一篇问答


2021-11-17更新
注意:在pycharm里,默认的source root就是项目根目录,这时不要在项目内部,再设置source folder了,要不然就会出现同一个Module,可以从不同级别import的问题。

我就曾经犯了这个错误,把一个项目子文件夹设置成source folder:pycharm source folder snapshot
导致自动生成的import,全都少一级目录,比如像下面这样:

from core.data.Action import Action
class Executor

而实际上写全路径也能成功import:

from simplerpa.core.data.Action import Action
class STATE

这个错误还很隐蔽,因为平时使用没有任何问题,直到有一个类成员属性承担了本文上面提到的ldict功能,但里面保存的变量,在Executor执行的时候都丢失了,才发现原来从不同路径import的同一个类,不能共享类成员。


songofhawk
303 声望24 粉丝