为什么必须创建一个新的全局变量来引用“ exec”中的当前类实例?

时间:2018-11-25 16:23:16

标签: python class global-variables instance self

我有一个包含约20个方法的类,在def __init__(self, ...):中,我不得不调用许多这些方法(〜9),但是我不想一个个地调用每个单独的方法。 / p>

因此,我采取了简单的方法,并创建了两个列表列表推导,使用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

通过反复试验,我发现了这一点;为了使此代码正常工作,我必须创建名为self的{​​{1}}的副本,并使新的instance变量成为全局变量,然后使用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

3 个答案:

答案 0 :(得分:4)

使用getattrexec更简单(通常更安全)。尝试以下方法:

def __init__(self):
    suffixes = ["ArticleObjects", "SeriesObjects", ...]
    for suffix in suffixes:
        method = getattr(self, "create" + suffix)
        method()

答案 1 :(得分:4)

这里有很多关于如何避免执行exec的好建议(通常是不好的),但是要回答有关为什么的问题,这与列表理解有更多关系。列表推导创建了一个新的作用域,当您在不使用globals或locals参数的情况下调用exec时,它将使用locals()函数:

  

注意:默认的本地语言按照下面的函数locals()描述

Source

在这里您可以从列表理解中看到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就没有这种运气了。

答案 2 :(得分:2)

我不会为此使用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")