8

我想执行一些 Python 代码,在运行时输入,所以我得到了字符串并调用

执行(pp,全局(),本地())

其中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:未定义全局名称“马”

有没有办法运行递归代码?

更新

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

4 回答 4

6

一开始这也让我感到惊讶,并且似乎是一个奇怪的极端情况,其中 exec 的行为既不像顶级定义,也不像封闭函数中的定义。看起来正在发生的事情是函数定义正在您传入的 locals() dict中执行。但是,定义的函数实际上并没有访问这个 locals dict。

通常,如果您在顶层定义函数,则局部变量和全局变量是相同的,因此函数在内部可见,因为它们可以在全局变量中看到函数。

当一个函数在另一个函数的作用域内定义时,python 会注意到它在函数内被访问,并创建一个闭包以便“马”映射到外部作用域中的绑定。

在这里,这是一个奇怪的中途案例。exec 就像定义在顶级一样,因此不会创建任何闭包。但是,由于局部变量与全局变量不同,因此定义不会出现在函数可以访问它的地方——它仅在不可访问的外部局部字典中定义。

你可以做几件事:

  1. 对本地人和全局人使用相同的字典。即“ exec s in locals(),locals()”(或者更好,只需使用您自己的字典)。仅提供 globals() dict 具有相同的效果 - 即 " exec s in mydict" #
  2. 将 func 放在它自己的函数中,这样就创建了一个闭包。例如

    s="""
    def go():
        def factorial(x):
            if x==0: return 1
            return x*factorial(x-1)
        print factorial(10)
    go()"""
    
  3. 正如斯蒂芬的回答所建议的那样,通过放置“全局 funcname”指令来强制函数进入 globals() 而不是 locals

于 2009-05-16T09:45:06.793 回答
5

这个对我有用:

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()
于 2009-05-16T07:30:48.567 回答
3

这对我有用(添加global rec)。rec(5)调用 local 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)
于 2009-05-16T08:30:27.423 回答
0

“NameError: global name 'rec' is not defined”意味着它在全局范围内寻找rec,而不是在本地范围内。看起来它是在本地范围内定义 rec ,然后尝试在全局范围内执行。尝试在您正在执行的字符串中打印 locals() 和 globals()。

更多信息。

于 2009-05-16T08:05:53.113 回答