Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining a function with exec from inside a function in global environment

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.

like image 604
TomCho Avatar asked Feb 17 '26 17:02

TomCho


2 Answers

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()
like image 120
Padraic Cunningham Avatar answered Feb 20 '26 06:02

Padraic Cunningham


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.

like image 24
Gil Hamilton Avatar answered Feb 20 '26 07:02

Gil Hamilton



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!