I have a function that, when called, should define another function with use of exec and make this new function available for the main program. The mwe is the following.
Main program:
#!/usr/bin/python
from ext import makeF
makeF()
sayA()
External module:
def makeF():
script="def sayA():\n\tprint 'Aah'"
exec(script)
sayA()
return
What I want is to be able to call the inner function sayA() from the main program, so in this example the output should be
Aah
Aah
but instead it returns
Aah
Traceback (most recent call last):
File "mwe.py", line 5, in <module>
sayA()
NameError: name 'sayA' is not defined
which I kind of expected, so I replace the exec(script) line with exec(script,globals), according to the docs, but instead I get
Traceback (most recent call last):
File "mwe.py", line 4, in <module>
makeF()
File "/home/tomas/tests/ext.py", line 3, in makeF
exec(script,globals,locals)
TypeError: exec: arg 2 must be a dictionary or None
I have the feeling I'm missing something pretty obvious here but I can't figure out. Any help is appreciated.
Thank you.
You have created the function inside makeF so it is not even visible in the scope of the external module outside the function.
If you want to call it from main, return sayA :
def makeF():
script="def sayA():\n\tprint('Aah')"
exec(script)
return sayA
Then in main:
f = makeF()
f()
To get the same behaviour in python3 where exec is no longer a statement but a function,you can use a lambda with a dict:
def makeF():
d = {}
"sayA = lambda: print('Aah')"
exec("sayA = lambda: print('Aah')",d)
return d["sayA"]
from ext import makeF
f = makeF()
f()
globals and locals() are functions, not dictionaries (though they return dictionaries).
But also, the way you were trying to invoke it, sayA is getting defined in locals(). Leave that out.
My version:
def makeF():
script="def sayA():\n\tprint 'Aah'"
#exec script in globals()
exec(script, globals())
#exec(script, globals(), locals())
sayA()
print globals()
print locals()
makeF()
sayA()
Try out the commented out lines for contrast.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With