在类中调用Python exec()时会在lambda上中断

在类中调用Python exec()时会在lambda上中断,python,lambda,exec,code-generation,Python,Lambda,Exec,Code Generation,我正在进行代码生成,最终得到的源代码字符串如下所示: class Proxy(object): def __init__(self,stdout,stringio): self._stdout = stdout self._stringio = stringio def __getattr__(self,name): if name in ('_stdout','_stringio','write'):

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

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
来源

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()
不工作

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
文件“”,第29行,在
文件“”,第27行,主
文件“”,第26行,在
NameError:未定义全局名称“add”

谢谢

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

无论如何,如果您专门为要在其中求值的表达式提供了一个作用域(这是一个很好的实践,这样您就不会污染您的命名空间),那么它在类中工作得很好

因此,替换该行:

    exec source

你应该是对的


在这里,我们提供了一个空字典,作为在表达式求值期间对globals()和locals()dctionary进行排序的基础。如果需要,您可以保留这本词典,或者像我在代码中演示的那样,让它立即被垃圾收集。以上链接中的exec文档对此进行了解释。

您是如何在类外执行它的?如果我在类内运行exec(source),它会破坏任何类。但是,如果我在外部运行它(不确定如何调用环境),正如我的示例中所示,它可以正常工作。您可以发布一个(非)工作示例,以便我们可以重现您的失败吗?@geogekouzmov那么问题在于您使用上下文管理器?为什么您要将dict分配给
sys.argv
sys.argv
是程序参数列表;在那里指定一个dict是没有意义的。@GeorgeKouzmov不客气。我应该补充一点,如果您保留字典,您将可以访问表达式中定义的函数。例如,您可以在mydict中的
exec source之后调用
print mydict['add'](1,2)
。我不知道这对你是否有用,但我想我会提一提的!