在递归函数中使用 exec()
我想在运行时执行一些Python代码,所以我获取一个字符串,然后调用
exec(pp, globals(), locals())
这里的pp就是那个字符串。这样做是没问题的,除了在递归调用的时候,比如说,下面这段代码是可以正常工作的:
def horse():
robot.step()
robot.step()
robot.turn(-1)
robot.step()
while True:
horse()
但是这段就不行:
def horse():
robot.step()
robot.step()
robot.turn(-1)
robot.step()
horse()
horse()
NameError: global name 'horse' is not defined
有没有办法让递归代码也能运行呢?
更新
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
如果把代码放在最外层是可以的。但如果把它放到一个函数里面:
def fn1():
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
fn1()
同样会出现这个错误:NameError: global name 'rec' is not defined
4 个回答
对我来说,这个方法有效(我加了 global rec
)。当我用 rec(5)
时,它会调用本地的 rec
函数,但如果我用 rec(n+1)
,它就会尝试调用一个全局的 rec
函数(这个函数并不存在)。
def fn1():
a = """global rec
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
这让我一开始也很惊讶,这似乎是一个奇怪的边缘情况,exec的表现既不像顶层定义,也不像封闭函数中的定义。看起来发生的事情是,函数定义是在你传入的locals()字典中执行的。然而,定义的函数实际上并不能访问这个locals字典。
通常情况下,如果你在顶层定义一个函数,locals和globals是一样的,所以函数可以在其中可见,因为它们能看到全局的函数。
当一个函数在另一个函数的范围内定义时,Python会注意到它在函数内被访问,并创建一个闭包,这样“horse”就会映射到外部范围中的绑定。
在这里,这是一个奇怪的中间情况。exec表现得好像定义是在顶层,所以没有创建闭包。然而,由于locals和globals并不相同,定义并没有去到函数可以访问的地方——它只是在不可访问的外部locals字典中定义。
你可以做几件事情:
- 使用同一个字典作为locals和globals。也就是说,"
exec s in locals(),locals()
"(或者更好,直接使用你自己的字典)。只提供一个globals()字典也有相同的效果——例如"exec s in mydict
"。 把函数放在自己的函数里面,这样就会创建一个闭包。例如:
s=""" def go(): def factorial(x): if x==0: return 1 return x*factorial(x-1) print factorial(10) go()"""
通过添加“global funcname”指令,强制函数进入globals()而不是locals,如stephan的回答所建议的。
对我来说,这个方法有效:
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a)
5
6
7
8
9
10
我只能说,你的代码里可能有个错误。
补充说明
给你看看这个:
def fn1():
glob = {}
a = """\
def rec(n):
if n > 10:
return
print n
return rec(n+1)
rec(5)"""
exec(a, glob)
fn1()