【问题标题】:Python exec() when called in class breaks on lambda在 lambda 的类中断中调用 Python exec()
【发布时间】:2014-02-03 06:29:57
【问题描述】:

我正在生成代码,最终得到一串如下所示的源代码:

来源

import sys
import operator

def add(a,b):
    return operator.add(a,b)

def mul(a,b):
    return operator.mul(a,b)

def saveDiv(a,b):
    if b==0:
        return 0
    else:
        return a/b

def subtract(a,b):
    return operator.sub(a,b)

def main(y,x,z):
   y = int(y)
    print y
    x = int(x)
    print x
    z = int(z)
    print z
    ind = lambda y,x,z: mul(saveDiv(x, add(z, z)), 1)
    return ind(y,x,z)

print main(**sys.argv)""

执行

当我使用exec() 执行代码,然后通过stdoutIO() 进行管道传输时

工作

args={'x':"1",'y':"1",'z':"1"}
source = getSource()
sys.argv = args
with stdoutIO() as s:
    exec source
s.getvalue

不工作

class Coder():

    def start(self):

        args={'x':"1",'y':"1",'z':"1"}

        source = getSource()
        sys.argv = args

        with stdoutIO() as s:
            exec source

        return s.getvalue

print "out:", Coder().start()

stdoutIO() 是这样实现的:

class Proxy(object):

    def __init__(self,stdout,stringio):
        self._stdout = stdout
        self._stringio = stringio

    def __getattr__(self,name):
        if name in ('_stdout','_stringio','write'):
            object.__getattribute__(self,name)
        else:
            return getattr(self._stringio,name)

    def write(self,data):
         self._stdout.write(data)
         self._stringio.write(data)

    @contextlib.contextmanager
    def stdoutIO(stdout=None):
        old = sys.stdout
        if stdout is None:
            stdout = StringIO.StringIO()
        sys.stdout = Proxy(sys.stdout,stdout)
        yield sys.stdout
        sys.stdout = old

问题

如果我在类之外执行执行代码,一切正常,但是当我在类中运行它时,它会因此错误而中断。如何解决或避免此问题?

  File "<string>", line 29, in <module>
  File "<string>", line 27, in main
  File "<string>", line 26, in <lambda>
  NameError: global name 'add' is not defined

谢谢

【问题讨论】:

  • 你是如何在课外执行的?
  • 如果我在一个类中运行 exec(source) ,它会破坏任何类。但是,如果我在外部运行它(不确定如何调用环境),如我的示例所示,它可以正常工作。
  • 您能否发布一个(非)工作示例,以便我们重现您的失败?
  • @GeorgeKouzmov 所以问题出在你使用上下文管理器吗?
  • 你为什么要给sys.argv分配一个字典? sys.argv 是程序参数列表;在那里分配一个字典是没有意义的。

标签: python lambda exec code-generation


【解决方案1】:

当您运行exec expression 时,它会在当前范围内执行expression 中包含的代码(请参阅here)。显然,在一个类中,表达式中的函数在运行 main 之前超出了范围。老实说,我不知道为什么(在我看来它应该可以工作)但也许有人可以在评论中添加完整的解释。

无论如何,如果您专门为要在其中计算的表达式提供了一个范围(无论如何,这是一种很好的做法,这样您就不会污染您的命名空间),它在类中可以正常工作。

所以,换行:

    exec source

    exec source in {}

你应该是对的!

在这里,我们在评估表达式期间提供一个空字典作为 globals() 和 locals() 字典。如果需要,您可以保留这本字典,或者像我在代码中演示的那样立即将其作为垃圾收集。这在上面链接的 exec 文档中都有解释。

【讨论】:

  • @GeorgeKouzmov 不客气。我应该补充一点,如果您保留字典,您将可以访问表达式中定义的函数。例如,您可以在exec source in mydictprint mydict['add'](1,2) 之后调用。不知道这对你有没有用,但我想我会提到它!
猜你喜欢
  • 2018-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-29
  • 2011-10-18
  • 1970-01-01
  • 1970-01-01
  • 2019-07-20
相关资源
最近更新 更多