Domanda

I'm doing code generation and I end up with a string of source that looks like this:

Source

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)""

Execution

When I'm executing code using exec() and then piping it through stdoutIO()

Working

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

Not Working

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()

And the stdoutIO() is implemented like this:

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

Problem

If I execute the execution code outside of the class everything works however when I run it inside a class it breaks with this error. How can I fix it or avoid this problem?

  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

Thanks

È stato utile?

Soluzione

When you run exec expression, it executes the code contained in expression in the current scope (see here). Apparently inside a class, the function in your expression are dropping out of scope before main is run. I honestly have no idea why (it seems to me like it should work) but maybe someone can add a complete explanation in a comment.

Anyway, if you specifically provide a scope for the expression to be evaluated in, (which is good practice anyway so that you don't pollute your namespace), it works fine inside the class.

So, replace the line:

    exec source

with

    exec source in {}

and you should be right!

Here we provide an empty dictionary as a the globals() and locals() dctionaries during the evaluation of your expression. You can keep this dictionary if you want, or let it be garbage collected immediately as I have demonstrated in my code. This is all explained in the exec documentation in the link above.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top