首页 > 解决方案 > 关于 Python 中递归的一些疑问

问题描述

顺便说一句,它是 python 中的井字游戏,它是一个处理用户不放置无效代码或不尝试在已占用的位置添加 X 或 O 的片段。所以在线视频中的讲师说你可以使用while循环来检查上面列出的问题所以我想为什么不使用递归当用户输入错误时,现在它在输出中显示了一些奇怪的东西

def handle_turn(player):

    position=input("Chooes a position from 1 to 9: ")
    if position not in ["1","2","3","4","5","6","7","8","9"]:
        print("Invalid Choice")
        handle_turn(player)
    # while position not in ["1","2","3","4","5","6","7","8","9"]:
    #     position=input("iNVALID CHOICE Chooes a position from 1 to 9: ")

    position=int(position)-1
    if board[position]!="_":
        print("you cannot go there")
        handle_turn(player)
    board[position]=player
    display_board()

输出:

从 1 到 9 选择一个位置:1
X | _ | _
_ | _ | _
_ | _ | _
从 1 到 9 选择一个位置:2
X | ○ | _
_ | _ | _
_ | _ | _
从 1 到 9 选择一个位置:3
X | ○ | X
_ | _ | _
_ | _ | _
从1到9选择一个位置:1
你不能去那里
从1到9选择一个位置:9
X | ○ | X
_ | _ | _
_ | _ | 哦哦
| ○ | X
_ | _ | _
_ | _ | O
从 1 到 9 选择一个位置:1
你不能去那里
从 1 到 9 选择一个位置:8
O | ○ | X
_ | _ | _
_ | X | 氧合
| ○ | X
_ | _ | _
_ | X | ○

标签: pythonpython-3.xpython-2.7recursion

解决方案


替换handle_turn(player)return handle_turn(player)

解释

为什么这很重要?考虑以下递归函数:

def f(n):
   print(' '*n + 'beginning of call {}'.format(n))
   if n < 5:
     f(n+1)
   print(' '*n + 'end of call {}'.format(n))

执行此函数会给出以下输出:

>>> f(0)
beginning of call 0
 beginning of call 1
  beginning of call 2
   beginning of call 3
    beginning of call 4
     beginning of call 5
     end of call 5
    end of call 4
   end of call 3
  end of call 2
 end of call 1
end of call 0

如您所见,一旦调用 5 的执行结束,流程返回到调用 4,调用 4 执行剩余的语句print(' '*n + 'end of call {}'.format(n));然后流程返回到调用 3,等等。

因为这个函数中没有return语句,所以函数中的所有语句都会被执行。在递归调用之前编写的语句在递归调用f(n+1)之前执行,在递归调用之后编写的语句在递归调用返回之后执行。

对于您的函数handle_turn,如果进行了递归调用,您不希望执行函数的其余部分。为了防止这种情况发生,您可以在递归调用之后立即添加一个 return 语句。考虑:

def g(n):
   print(' '*n + 'beginning of call {}'.format(n))
   if n < 5:
     g(n+1)
     return
   print(' '*n + 'end of call {}'.format(n))

或等效地:

def g(n):
   print(' '*n + 'beginning of call {}'.format(n))
   if n < 5:
     return g(n+1)
   print(' '*n + 'end of call {}'.format(n))

这个新函数的输出将是:

>>> g(0)
beginning of call 0
 beginning of call 1
  beginning of call 2
   beginning of call 3
    beginning of call 4
     beginning of call 5
     end of call 5

如您所见,调用 0 到 4 的其余语句没有被执行,因为这些调用的执行缩短了return内部语句。if

如果您想练习并享受没有返回语句的递归函数并在递归调用后始终执行所有剩余语句的递归函数,我建议您可以在线玩关于由递归函数控制的机器人的游戏“RoboZZle”。最难的谜题大量使用递归函数的这种行为。

尾递归

在上一段中,我说过一行return g(n+1)和两行g(n+1) \\ return是等价的。在大多数语言中,严格来说这不是真的,因为这两个表达式之一使用尾递归,而另一个没有。Python 根本没有尾递归,所以这种区别在这里无关紧要。

一个后果是,您可以预期大量使用递归的程序在 Python 中会相当慢,甚至在某些情况下会崩溃。在您的示例中这不是问题,因为递归取决于用户输入,如果用户是人类,用户将始终比您的程序慢。但如果用户是另一个程序,这可能是个问题。


推荐阅读