I am trying to run this code but it seems that the exec()
is not executing the string inside the function:
def abc(xyz):
for i in fn_lst:
s = 'temp=' + i + '(xyz)'
exec(s)
print (temp)
abc('avdfbafadnf')
The error I am receiving:
NameError Traceback (most recent call last)
<ipython-input-23-099995c31c78> in <module>()
----> 1 abc('avdfbafadnf')
<ipython-input-21-80dc547cb34f> in abc(xyz)
4 s = 'temp=' + i + '(word)'
5 exec(s)
----> 6 print (temp)
NameError: name 'temp' is not defined
fn_lst
is a list of function names i.e: ['has_at', 'has_num' ...]
Please let me know an alternative to exec()
if possible in such a scenario.
I would like to mention that many "standard" answers, previously suggested in this topic, do not work inside a function. For example, consider the following code snippet:
def test():
exec( 'a = 3', globals(), locals() )
print(a)
test()
Everything seems fine. However, this code gives an error in Python 3:
NameError: name 'a' is not defined
I tried some methods using the compile
function suggested in other forums, but they still do not work for me (at least with the options I have seen mentioned).
According to my research, this the closest code that I have seen working:
def test():
lcls = locals()
exec( 'a = 3', globals(), lcls )
a = lcls["a"]
print(f'a is {a}')
test()
It successfully prints:
a is 3
I think this is an important topic overall. Sometimes when you work with symbolic algebra libraries, like Sympy, defining variables though the exec
function can be very convenient for Scientific Computing.
I hope somebody knows a good answer to the problem.
EDIT:
Nowadays, I rarely use exec
anymore. I have realized that a better/shorter solution to the OP question is to simply define local variables using the eval
function. The code of the OP could have been written as:
def abc(xyz):
for i in fn_lst:
temp = eval(i + '(xyz)')
print (temp)
abc('avdfbafadnf')
# problem solved :)
Since the variable name temp
was already hard-coded into the function, using eval
doesn't change the generality of the solution. If the name of the variable isn't known beforehand, eval
can also be used as follows:
def advanced_eval(expr):
var_names = expr.split('=')[0].replace(' ','')
rhs_values = eval('='.join(expr.split('=')[1:]))
return var_names, rhs_values
If you define name,value = advanced_eval('a=3+3')
, the code will effectively output that name = 'a'
and value = 6
.
First we show how to make a variable set by the string passed to exec(), available outside of the call to exec(). And then we show some examples of how to make a variable available outside of a call to a function that calls exec().
The central concepts include that exec() takes as arguments, the string to be executed and two dictionaries to serve as global and local scope.
For example, we can pass the actual global and local scope, like this:
exec( 'a = 3', globals(), locals() )
print( a )
This will print the following result:
3
However, there is considerable flexibility in what dictionaries we choose to pass to exec(), and this provides a few ways to set a variable in the local scope from a function that calls exec().
For example, we can pass the current local scope to a function and then use that as the local dictionary for exec(), like this:
def demofunction( adict ):
exec( 'a=1.', globals(), adict )
print( 'before calling the function' )
try:
print( a )
except Exception as e:
print( e )
demofunction( locals() )
print( 'after calling the function' )
print( 'a =', a )
This prints:
before calling the function
name 'a' is not defined
after calling the function
a = 1.0
Since the calling scope is global to the scope inside the function, another simple way to set a local variable from inside a function, is to just use globals() as the second argument for exec().
def demofunction( adict ):
exec( 'a=1.', None, globals() )
print( 'before calling the function' )
try:
print( a )
except Exception as e:
print( e )
demofunction( locals() )
print( 'after calling the function' )
print( 'a =', a )
And this again, prints:
before calling the function
name 'a' is not defined
after calling the function
a = 1.0
So, we see that exec() in fact, can create variables in our local scope from inside a function.
Also, you are not limited to globals() and locals(). You can pass it any valid dictionary.
def demofunction( adict ):
exec( 'a=1.', None, adict )
somedict = { 'b': 1 }
print( somedict )
demofunction( somedict )
print( somedict )
Now the output is:
{'b': 1}
{'b': 1, 'a': 1.0}
Note: In the first examples it would have been sufficient to use the local argument alone, i.e. omitting globals(). Both were included here to illustrate the more general case. You can read about "Scope" in Python, in the Python Textbook - Scope
After spending so much time doing hit and trial on this problem, I can say that using exec like this was working without any problem inside function, otherwise it threw error. I have tested this for both functions and variables.
def main():
x = "def y():\n\treturn('This will work')"
#pass only globals() not locals()
exec(x,globals())
print(y())
main()
def test():
#pass only globals() not locals()
exec( 'a = 3', globals())
print(a)
test()
Here is a screenshot of this working on W3School's online interpreter (you can copy/paste and test it here yourself)
Instead of using exec
with function names, just keep the function objects in the list:
fn_lst = [has_at, has_num, ...]
and perform the call directly:
def abc(xyz):
for i in fn_lst:
temp= i(xyz)
print(temp)
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