为用户输入递归调用函数

时间:2020-12-06 18:22:40

I'm trying to make a rock-paper-scissors game, and am trying to verify the input.

我正在尝试制作一个石头剪刀游戏,并试图验证输入。

def player1():
    x = (raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ")).lower()
    if x == 'r' or x == 'p' or x == 's' or x == 'rock' or x == 'paper' or x == 'scissors':
        return x[0]
    else:
        print "Error - wrong input!"
        player1() #I know I can run a While loop, but I need to run it this way.

print(player1())

If I enter the right input on the first try, everything works fine. But if I enter wrong input on first try, and enter the right input on the second time, I get None in the output, instead of the first letter of the RPS options.

如果我在第一次尝试时输入正确的输入,一切正常。但是如果我在第一次输入时输入错误的输入,并在第二次输入正确的输入,我在输出中得到None,而不是RPS选项的第一个字母。

What am I missing?

我错过了什么?

4 个解决方案

#1


You're going to want to loop on input. What you're doing currently is recursively calling player1, and the recursive case doesn't have an explicit return value (hence, None is returned).

你想要循环输入。你当前正在做的是递归调用player1,并且递归的情况没有显式的返回值(因此,返回None)。

The way you do this is simple: while there is invalid input, prompt again. I'm using a modified version of this in the vein of the "while True break" style; it accomplishes the same goal. We loop indefinitely, and if the condition we want is valid, we return; otherwise, we prompt for input and loop again.

你这样做很简单:当输入无效时,再次提示。我正在使用这种修改版本的“while True break”风格;它实现了同样的目标。我们无限循环,如果我们想要的条件有效,我们返回;否则,我们提示输入并再次循环。

def player1():
    while True:
        x = raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ").lower()
        if x == 'r' or x == 'p' or x == 's' or x == 'rock' or x == 'paper' or x == 'scissors':
            return x[0]
        else:
            print "Error - wrong input!"

As an alternative to that if statement, there is a slightly more clean way to express it via the in operator.

作为if语句的替代方法,有一种更简洁的方式通过in运算符表达它。

if x in ('r', 'p', 's', 'rock', 'paper', 'scissors'):

As an addendum to your original question (as it says that you have to do it recursively), I must strongly caution you against doing any input evaluation through recursion. Python has a call stack size of around 1,000, which means that you have a very finite (yet reasonably large) amount of tries before the program irrecoverably crashes.

作为原始问题的补充(因为它表示你必须递归地执行),我必须强烈提醒你不要通过递归进行任何输入评估。 Python的调用堆栈大小约为1,000,这意味着在程序无法恢复崩溃之前,您有一个非常有限(但相当大)的尝试次数。

Not just that, but your operation stack will be unnecessarily filled with method calls that behave in a similar fashion to a loop. For memory's sake in addition to the absolute recursion ceiling, do not use recursion for this.

不仅如此,您的操作堆栈将不必要地填充方法调用,其行为方式与循环类似。为了记忆,除了绝对递归上限之外,不要为此使用递归。

If you absolutely must, and again I strongly advise against doing this, then you simply have to return from your iterative case.

如果你绝对必须,我强烈建议不要这样做,那么你只需要从你的迭代案例中返回。

def player1():
    x = (raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ")).lower()
    if x == 'r' or x == 'p' or x == 's' or x == 'rock' or x == 'paper' or x == 'scissors':
        return x[0]
    else:
        print "Error - wrong input!"
        return player1() #I know I can run a While loop, but I need to run it this way.

print(player1())

#2


An improved version of @Makoto's example:

@ Makoto的改进版本示例:

def player1():
    x = raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ").lower()
    while True:
        if x in ['r', 'p', 's', 'rock', 'paper', 'scissors']:
            return x[0]
        else:
            print "Error - wrong input!"
            x = raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ").lower()

This is a little more concise than many or expressions which gets a bit unwieldy if you have a lot of conditions you want to check!

这比许多或表达更简洁,如果你想要检查很多条件,它会变得有点笨拙!

A little explanation:

一点解释:

We're checking to see x (our user input) is in pre-defined list of valid inputs.

我们正在检查x(我们的用户输入)是否在预定义的有效输入列表中。

An even more generalized version of this which becomes reusable:

一个更加通用的版本,可以重复使用:

Example: (reusable, non-recursion:)

示例:(可重用,非递归:)

#!/usr/bin/env python


from __future__ import print_function  # For Python 2/3 compat


try:
    input = raw_input  # For Python 2/3 compat
except NameError:
    pass


def prompt(prompt="Enter: ", valid=None):
    s = input(prompt)
    while valid and s not in valid:
        print("Invalid input! Please try again. Valid inputs are {0:s}".format(" ".join(valid)))
        s = input(prompt)
    return s


x = prompt("Enter action ([r]ock, [p]aper, [s]cissors): ", ["r", "p", "s", "rock", "paper", "scissors"])

Demo:

$ python foo.py
Enter action ([r]ock, [p]aper, [s]cissors): a
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): foo
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): r

$ python foo.py
Enter action ([r]ock, [p]aper, [s]cissors): a
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): foo
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): rock

PS: Sorry I didn't answer your question using recursion. IHMO this is not a good use-case for recursion. Oh well :) However; this is pretty easy to change:

PS:对不起,我没有用递归回答你的问题。 IHMO这不是递归的好用例。哦,好吧:)但是;这很容易改变:

Example: (reusable, recursive)

示例:(可重用,递归)

def userprompt(prompt="Enter: ", valid=None):
    s = input(prompt)
    while valid and s not in valid:
        print("Invalid input! Please try again. Valid inputs are {0:s}".format(" ".join(valid)))
        s = userprompt(prompt, valid)
    return s

#3


In the else branch your function (the first call to your function, in particular) doesn’t return anything. In Python functions that do not return anything always return None implicitly.

在else分支中,您的函数(特别是对函数的第一次调用)不会返回任何内容。在Python中,不返回任何内容的函数总是隐式返回None。

#4


I'm adding this answer for completeness sake, as you do ask for a recursive solution. Here is my solution that is closest to yours:

为了完整起见,我正在添加这个答案,因为你要求递归解决方案。这是我最接近你的解决方案:

def player1():
    x = (raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ")).lower()
    if x == 'r' or x == 'p' or x == 's' or x == 'rock' or x == 'paper' or x == 'scissors':
        return x[0]
    else:
        print "Error - wrong input!"
        return player1()

As you can see, all you've forgotten is a return statement. A more readable way might be:

正如你所看到的,你所遗忘的只是一个回报声明。更可读的方式可能是:

def player1():
    playerInput=None
    while playerInput not in ('r', 'p', 's', 'rock', 'paper', 'scissors'):
        if playerInput is not None:
            print("Error - wrong input!")
        playerInput = raw_input("please select: Rock(r)/Paper(p)/Scissors(s)").lower()
    return playerInput[0]

It would be even cleaner with a do while loop, but python lacks that construct.

使用while循环会更清晰,但python缺少该构造。

#1


You're going to want to loop on input. What you're doing currently is recursively calling player1, and the recursive case doesn't have an explicit return value (hence, None is returned).

你想要循环输入。你当前正在做的是递归调用player1,并且递归的情况没有显式的返回值(因此,返回None)。

The way you do this is simple: while there is invalid input, prompt again. I'm using a modified version of this in the vein of the "while True break" style; it accomplishes the same goal. We loop indefinitely, and if the condition we want is valid, we return; otherwise, we prompt for input and loop again.

你这样做很简单:当输入无效时,再次提示。我正在使用这种修改版本的“while True break”风格;它实现了同样的目标。我们无限循环,如果我们想要的条件有效,我们返回;否则,我们提示输入并再次循环。

def player1():
    while True:
        x = raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ").lower()
        if x == 'r' or x == 'p' or x == 's' or x == 'rock' or x == 'paper' or x == 'scissors':
            return x[0]
        else:
            print "Error - wrong input!"

As an alternative to that if statement, there is a slightly more clean way to express it via the in operator.

作为if语句的替代方法,有一种更简洁的方式通过in运算符表达它。

if x in ('r', 'p', 's', 'rock', 'paper', 'scissors'):

As an addendum to your original question (as it says that you have to do it recursively), I must strongly caution you against doing any input evaluation through recursion. Python has a call stack size of around 1,000, which means that you have a very finite (yet reasonably large) amount of tries before the program irrecoverably crashes.

作为原始问题的补充(因为它表示你必须递归地执行),我必须强烈提醒你不要通过递归进行任何输入评估。 Python的调用堆栈大小约为1,000,这意味着在程序无法恢复崩溃之前,您有一个非常有限(但相当大)的尝试次数。

Not just that, but your operation stack will be unnecessarily filled with method calls that behave in a similar fashion to a loop. For memory's sake in addition to the absolute recursion ceiling, do not use recursion for this.

不仅如此,您的操作堆栈将不必要地填充方法调用,其行为方式与循环类似。为了记忆,除了绝对递归上限之外,不要为此使用递归。

If you absolutely must, and again I strongly advise against doing this, then you simply have to return from your iterative case.

如果你绝对必须,我强烈建议不要这样做,那么你只需要从你的迭代案例中返回。

def player1():
    x = (raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ")).lower()
    if x == 'r' or x == 'p' or x == 's' or x == 'rock' or x == 'paper' or x == 'scissors':
        return x[0]
    else:
        print "Error - wrong input!"
        return player1() #I know I can run a While loop, but I need to run it this way.

print(player1())

#2


An improved version of @Makoto's example:

@ Makoto的改进版本示例:

def player1():
    x = raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ").lower()
    while True:
        if x in ['r', 'p', 's', 'rock', 'paper', 'scissors']:
            return x[0]
        else:
            print "Error - wrong input!"
            x = raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ").lower()

This is a little more concise than many or expressions which gets a bit unwieldy if you have a lot of conditions you want to check!

这比许多或表达更简洁,如果你想要检查很多条件,它会变得有点笨拙!

A little explanation:

一点解释:

We're checking to see x (our user input) is in pre-defined list of valid inputs.

我们正在检查x(我们的用户输入)是否在预定义的有效输入列表中。

An even more generalized version of this which becomes reusable:

一个更加通用的版本,可以重复使用:

Example: (reusable, non-recursion:)

示例:(可重用,非递归:)

#!/usr/bin/env python


from __future__ import print_function  # For Python 2/3 compat


try:
    input = raw_input  # For Python 2/3 compat
except NameError:
    pass


def prompt(prompt="Enter: ", valid=None):
    s = input(prompt)
    while valid and s not in valid:
        print("Invalid input! Please try again. Valid inputs are {0:s}".format(" ".join(valid)))
        s = input(prompt)
    return s


x = prompt("Enter action ([r]ock, [p]aper, [s]cissors): ", ["r", "p", "s", "rock", "paper", "scissors"])

Demo:

$ python foo.py
Enter action ([r]ock, [p]aper, [s]cissors): a
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): foo
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): r

$ python foo.py
Enter action ([r]ock, [p]aper, [s]cissors): a
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): foo
Invalid input! Please try again. Valid inputs are r p s rock paper scissors
Enter action ([r]ock, [p]aper, [s]cissors): rock

PS: Sorry I didn't answer your question using recursion. IHMO this is not a good use-case for recursion. Oh well :) However; this is pretty easy to change:

PS:对不起,我没有用递归回答你的问题。 IHMO这不是递归的好用例。哦,好吧:)但是;这很容易改变:

Example: (reusable, recursive)

示例:(可重用,递归)

def userprompt(prompt="Enter: ", valid=None):
    s = input(prompt)
    while valid and s not in valid:
        print("Invalid input! Please try again. Valid inputs are {0:s}".format(" ".join(valid)))
        s = userprompt(prompt, valid)
    return s

#3


In the else branch your function (the first call to your function, in particular) doesn’t return anything. In Python functions that do not return anything always return None implicitly.

在else分支中,您的函数(特别是对函数的第一次调用)不会返回任何内容。在Python中,不返回任何内容的函数总是隐式返回None。

#4


I'm adding this answer for completeness sake, as you do ask for a recursive solution. Here is my solution that is closest to yours:

为了完整起见,我正在添加这个答案,因为你要求递归解决方案。这是我最接近你的解决方案:

def player1():
    x = (raw_input("please select: Rock(r)/Paper(p)/Scissors(s): ")).lower()
    if x == 'r' or x == 'p' or x == 's' or x == 'rock' or x == 'paper' or x == 'scissors':
        return x[0]
    else:
        print "Error - wrong input!"
        return player1()

As you can see, all you've forgotten is a return statement. A more readable way might be:

正如你所看到的,你所遗忘的只是一个回报声明。更可读的方式可能是:

def player1():
    playerInput=None
    while playerInput not in ('r', 'p', 's', 'rock', 'paper', 'scissors'):
        if playerInput is not None:
            print("Error - wrong input!")
        playerInput = raw_input("please select: Rock(r)/Paper(p)/Scissors(s)").lower()
    return playerInput[0]

It would be even cleaner with a do while loop, but python lacks that construct.

使用while循环会更清晰,但python缺少该构造。

相关文章