I want to execute some Python code, typed at runtime, so I get the string and call
exec(pp, globals(), locals())
where pp is the string. It works fine, except for recursive calls, e. g., for example, this code is OK:
def horse():
robot.step()
robot.step()
robot.turn(-1)
robot.step()
while True:
horse()
But this one is not:
def horse():
robot.step()
robot.step()
robot.turn(-1)
robot.step()
horse()
horse()
NameError: global name 'horse' is not defined
Is there a way to run recursive code as well?
UPDATE
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
Works if put on the top-level. But if moved inside a function:
def fn1():
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
fn1()
the same error occurs: NameError: global name 'rec' is not defined
So, what is recursion? A recursive function is a function that calls itself until a “base condition” is true, and execution stops.
The syntax for recursive function is: function recurse() { // function code recurse(); // function code } recurse(); Here, the recurse() function is a recursive function. It is calling itself inside the function.
In C programming, a function is allowed to call itself. A function which calls itself directly or indirectly again and again until some specified condition is satisfied is known as Recursive Function. A recursive function is a function defined in terms of itself via self-calling expressions.
Simple examples of a recursive function include the factorial, where an integer is multiplied by itself while being incrementally lowered. Many other self-referencing functions in a loop could be called recursive functions, for example, where n = n + 1 given an operating range.
This surprised me too at first, and seems to be an odd corner case where exec is acting neither quite like a top-level definition, or a definition within an enclosing function. It looks like what is happening is that the function definition is being executed in the locals() dict you pass in. However, the defined function does not actually have access to this locals dict.
Normally, if you define a function at the toplevel, locals and globals are the same, so functions are visible within because they can see the function in the globals.
When a function is defined within another function's scope, python will notice that it is accessed within the function, and create a closure so that "horse" maps to the binding in the outer scope.
Here, it's a weird halfway case. exec is acting as if the definitions are at top-level, so no closures are created. However, since locals is not the same as globals, the definition doesn't go where the function can access it - its defined only in the inaccessible outer locals dict.
There are a couple of things you could do:
exec s in locals(),locals()
" (or better, just use your own dict). Providing only a globals() dict has the same effect - ie "exec s in mydict
"
#Put the func inside its own function, so that a closure is created. eg
s="""
def go():
def factorial(x):
if x==0: return 1
return x*factorial(x-1)
print factorial(10)
go()"""
Force the function to go into globals() rather than locals by putting a "global funcname" directive, as suggested by stephan's answer
It works for me:
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
5
6
7
8
9
10
All I can say is that there is probably a bug in your code.
Edit
Here you go
def fn1():
glob = {}
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a, glob)
fn1()
This works for me (added global rec
). rec(5)
calls the local rec
, but rec(n+1)
calls a global rec (which doesn't exist) without it.
def fn1():
a = """global rec
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
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