【问题标题】:Using exec() with recursive functions将 exec() 与递归函数一起使用
【发布时间】:2010-10-26 16:37:12
【问题描述】:

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

exec(pp, globals(), locals())

其中 pp 是字符串。它工作正常,除了递归调用,例如。 g.例如,这段代码是可以的:

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: 全局名称 'horse' 不是 定义

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

更新

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

【问题讨论】:

  • 请告诉我这个执行字符串不是来自用户输入。

标签: python recursion exec


【解决方案1】:

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

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

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

在这里,这是一个奇怪的中途案例。 exec 就像定义在顶级一样,因此不会创建任何闭包。但是,由于 locals 与 globals 不同,因此定义不会到达函数可以访问它的位置 - 它仅在不可访问的外部 locals 字典中定义。

你可以做几件事:

  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. 按照stephan's answer 的建议,通过放置“global funcname”指令强制函数进入 globals() 而不是 locals。

【讨论】:

    【解决方案2】:

    它对我有用:

    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()
    

    【讨论】:

    • @Headcrab,因为它为您提供了一个可编辑的全局和局部字典。 locals() 为您提供了一个无法更改“真实”局部变量的字典。
    • 你的意思是,如果“globals”不存在,exec 会使用一些默认的只读选项,并且“rec”不能添加到那里(因为它是只读的),那就是为什么会出现错误?
    • @Headcrab,我相信这是正确的。 Exec 假定对变量的调用是全局变量,因为它看不到它包含在函数中。真正让我感到困惑的是为什么 exec(a, globals()) 似乎可以工作,这表明存在 locals() 问题。
    • 这实际上与 locals 是只读的无关 - 只要您使用单独的字典来存储 locals 和 globals,就会发生这种情况。 {} 中的 exec ,{} 也会有同样的问题。 exec(a, globals()) 之所以有效,是因为它与 exec(a, globals(), globals()) 相同,因此本地定义也放入全局变量中。
    【解决方案3】:

    这对我有用(添加了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)
    

    【讨论】:

      【解决方案4】:

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

      More info.

      【讨论】:

        猜你喜欢
        • 2020-10-22
        • 2019-12-11
        • 2017-01-15
        • 1970-01-01
        • 2019-10-01
        • 1970-01-01
        • 2019-12-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多