我有一个包含 ~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 语句(这通常是不好的)的好建议,但是要回答您关于为什么会发生这种情况的问题,它更多地与列表理解有关。列表理解创建一个新的范围,当你调用 exec 时没有全局或本地参数,它使用 locals() 函数:
Note: The default locals act as described for function locals() below
在这里,您可以从列表理解中看到 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,就没有这样的运气了。
