Python:递归函数中的变量绑定

3 投票
3 回答
637 浏览
提问于 2025-04-18 18:28

我在使用一个类似下面的函数时,遇到了一些奇怪的情况:

    def foo(x):
        if int(x)!=4:
            x = raw_input("Wrong guess, please enter new value: " )
            foo(x)
        else:
            print "Good Job! %s was right"%x
        return x

    value = foo(x=raw_input("Guess a Number between 1 and 10: "))
    print value

比如说,如果我输入“1”,然后“2”,接着“3”,最后“4”,我得到的输出是:

Good Job! 4 was right
2

这让我感到困惑,因为这个函数似乎能正确识别出答案,但在识别之后,它却返回了第二个输入的值,而不是最新的那个。

有没有人能解释一下这个递归函数中“x”的绑定到底是怎么回事?

3 个回答

2

试试下面的代码:

def foo(x):
    if int(x)!=4:
        x = raw_input("Wrong guess, please enter new value: " )
        return foo(x)
    else:
        print "Good Job! %s was right"%x
        return x

value = foo(x=raw_input("Guess a Number between 1 and 10: "))
print value

你可以把每次调用函数 foo 看作是创建了一个新的变量 x。因此,递归调用会生成一系列的变量,比如 x1、x2、x3,等等。所以当一个函数调用结束后,你的局部变量 x 并没有改变。这就是为什么你得到的结果是 2,而不是最后一次递归调用的赋值结果(4)。如果你想在函数中改变传入的变量,你需要通过引用(或者对象)来传递它,而不是通过值来传递。想了解更多细节,可以看看这篇文章。

3

主要问题是你在

def foo(x):
    if int(x)!=4:
        x = raw_input("Wrong guess, please enter new value: " )
        foo(x) # <-- need return
    else:
        print "Good Job! %s was right"%x
    return x

value = foo(x=raw_input("Guess a Number between 1 and 10: "))
print value

这里缺少一个 return

发生的事情是,它调用了 foo(1),这个值不等于4,然后把 x 赋值为2,而这就是 x 最后得到的值,所以

  • 你的递归函数 foo(x) 返回了一个值,但这个值没有被赋给任何东西,也没有从递归调用中返回。
  • 最后 x 得到的值是2,所以最开始的 foo(1) 返回的就是这个值。

所以你可以选择

x = foo(x)

或者

return foo(x)

在我标记的那一行

4

让我们来看看吧!

value = foo(raw_input())
# foo is the same as in the question, I won't repeat it here
print value

在你的 foo 函数里面,你会得到这个:

# foo(1) calls foo(2) and sets x to 2
# foo(2) calls foo(3) and sets x to 3
# foo(3) calls foo(4) and sets x to 4
# foo(4) does:
print "Good Job! 4 was right"
return 4 # to foo(3)
# foo(3) does:
return 4 # to foo(2)
# foo(2) does:
return 3 # to foo(1)
# foo(1) does:
return 2 # to main

因为从最外层的递归返回给 main 的值是 2,所以 value 就保持这个值。

要解决这个问题,你可以选择把它改成循环的方式:

def iter_foo(x):
    while int(x) != 4:
        x = raw_input("Wrong guess. Try again! ")
    print "Good Job! %s was right" % x
    return x

或者让每一次递归都返回新函数的结果

def recurse_foo(x):
    if int(x) != 4:
        return foo(raw_input("Wrong guess. Try again! "))
    else:
        print "Good Job! %s was right!" % x
        return x

撰写回答