I am trying to dynamically create 2 functions defined within a string. Code:
def main():
fns = '''
def plus_one(x):
return x + 1
def plus_two(x):
return plus_one(x) + 1
'''
exec(fns)
result = eval('plus_two(11)')
print(result)
if __name__ == '__main__':
main()
Saving this code to a file called dyn_code.py
and running it gives me the following error:
python dyn_code.py
Traceback (most recent call last):
File "dyn_code.py", line 19, in <module>
main()
File "dyn_code.py", line 14, in main
result = eval('plus_two(11)')
File "<string>", line 1, in <module>
File "<string>", line 7, in plus_two
NameError: name 'plus_one' is not defined
Problem here is that plus_one
cannot be resolved inside plus_two
.
plus_one
on its own is fine here and can be called with the correct result.
Can anybody please give me an idea on how to inject code like this into the local namespace? Specifically, I want to create 2 functions, with one referring to the other.
I have intentionally used the most open form of both exec
and eval
, I do know how to restrict them, etc. I have also verified that after the call to exec
both functions are present in the local namespace.
What makes this more frustrating is that the code works fine in an interpreter session! That is, after injecting these 2 functions into the interpreter namespace via exec
, plus_two
runs without any issues.
Ideally, I would like to avoid a function-in-function scenario i.e.
def plus_two(x):
def plus_one(x):
return x + 1
return plus_one(x) + 1
This technique actually works but I want 2 explicitly named and standalone functions.
indentations of your function in fns
matters! and you have to pass globals()
optional argument for mapping!
def main():
fns = '''def plus_one(x):
return x + 1
def plus_two(x):
return plus_one(x) + 1
'''
exec(fns,globals())
result = eval('plus_two(11)')
print(result)
if __name__ == '__main__':
main()
Output:
13
Hope it helps!