简体   繁体   中英

Python: Is it good practice to call a function within itself?

Just a beginner question about good practice.

Take this bit of code for example. I want a particular user input, and if they enter something crazy, I obviously want to run the code inside the function again.

def get_difficulty():
    chosen_difficulty = str(raw_input("***  Choose difficulty: Easy, Medium or Hard: ").lower())
    if chosen_difficulty == "hard":
        return 10
    elif chosen_difficulty == "medium":
        return 15
    elif chosen_difficulty == "easy":
        return 20       
    else:
        print "***  Did you enter 'Easy', 'Medium' or 'Hard'?"
        print "***  Sorry that was passive aggressive. You obviously didn't..."
        return get_difficulty() 

Is it ok to make the function handle the else case like this? It seems inelegant; if the person entered something wrong five times the function would be nested 5 times and eventually the right answer would have to cascade down through the return of each function.

It works fine, but is there a better way?

In your case a loop is the correct way to handle repeated input:

def get_difficulty():
    while True:
        chosen_difficulty = raw_input("***  Choose difficulty: Easy, Medium or Hard: ").lower()
        try:
            return {"hard": 10, "medium": 15, "easy": 20}[chosen_difficulty]
        except KeyError:
            print "***  Did you enter 'Easy', 'Medium' or 'Hard'?"
            print "***  Sorry that was passive aggressive. You obviously didn't..."

What you discovered is called "recursion" and there is fundamentally nothing wrong about it. It is a strong concept that often leads to elegant formulation of problems. The Fibonacci numbers are an often presented problem that is easily solvable with recursion: We want to generate the number sequence 1, 1, 2, 3, 5, 8, 13, .. so the n+1 entry is (n-1) + (n). This leads to the following algorithm:

def fibonacci(n):
    """Generate the n-th fibonacci number"""
    if n == 0 or n == 1:
        return(1)
    else:
        return(fibonacci(n-2) + fibonacci(n-1))

Every recursive function can be turned into an iterative one. For the n-th fibonacci sequence there exists a closed form, you can look it up in the wikipedia article . As you see there are two "irrational numbers" that can be expressed by sum/division of square root of two. So sometimes problems are "recursive by nature" and recursive solutions can be short, where as a iterative solution might "look ugly"/"be longer".

So recursion is in general a good thing, but in python it is not always a good solution. As you already pointed out, if a user inserts five time a wrong input the function stack will have five function calls. Python has a max recurion depth and if a user would enter consecutively wrong input he could crash the program. In case of user input this is not realy a problem, but in other cases you can run more easily into the maximal recursion depth.

Tail-recursion (which is not implemented in python) is a way to allow for arbitrary recursion depths. Haskell and lisp uses this concept, you can read more on wikipedia or this stackoverflow post .

The canonical way to handle input verification in python is a while loop as pointed out by Daniel.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM