我有一个包含大约20个方法的类,在def __init__(self, ...):
中,我必须调用其中的许多方法(大约9个(,但我不想逐个调用每个单独的方法。
因此,我采取了简单的方法,创建了两个列表列表理解,使用exec
调用每个方法:
[exec("self.create%s()" % x) for x in "ArticleObjects SeriesObjects ArticleList SearchList".split(" ")]
[exec("self.compile%sPage(self)" % x) for x in "About Screenshots Search Contact Articles".split(" ")]
当我使用python3 filename.py
运行此代码时,我得到了一个错误,内容为:
NameError: name 'self' is not defined
经过反复试验,我发现;为了让这个代码工作起来,我必须创建一个名为instance
的self
副本,并将新的instance
变量设置为全局变量,然后使用ClassName.methodName(instance)
而不是self.methodName()
:调用该方法
工作代码为:
global instance; instance = self
[exec("ClassNamecreate%s(instance)" % x) for x in "ArticleObjects SeriesObjects ArticleList SearchList".split(" ")]
[exec("ClassName.compile%sPage(instance)" % x) for x in "About Screenshots Search Contact Articles".split(" ")]
为什么会这样?为什么self
变量在exec
中未定义,尽管它可用于调用exec
的范围?
更新:我使用的是Python 3.6.7
这里有很多关于如何避免exec语句(通常是不好的(的好建议,但要回答您关于为什么会发生这种情况的问题,更多的是与列表理解有关。列表理解创建了一个新的作用域,当您在没有globals或locals参数的情况下调用exec时,它会使用locals()
函数:
注意:默认的locals与下面的函数locals((所描述的一样
源
在这里,您可以从列表理解中看到locals()
函数的结果:
class Sample:
def __init__(self):
k = 4
print(locals())
exec("print(locals())")
[print(locals()) for x in range(1)]
[exec("print(locals())") for x in range(1)]
Sample()
输出:
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'k': 4, 'self': <__main__.Sample object at 0x00000000030295C0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
{'x': 0, '.0': <range_iterator object at 0x00000000030019F0>}
因此,locals()
在exec内部或外部都是相同的。是列表理解改变了它。只有当你在exec语句之外时,解释器才能越过列表理解的局部,在外部范围中找到self
。一旦你打电话给exec,就没有这样的运气了。
使用getattr
比exec
更简单(通常更安全(。尝试以下方法:
def __init__(self):
suffixes = ["ArticleObjects", "SeriesObjects", ...]
for suffix in suffixes:
method = getattr(self, "create" + suffix)
method()
我不会为此使用exec
。虽然它可能是最短的版本,但它也可能混淆合作者和代码分析工具。我会用这样的东西代替:
class Test:
def __init__(self):
for f in (self.createA, self.createB, self.createC):
f()
def createA(self):
print("A")
def createB(self):
print("B")
def createC(self):
print("C")