109

I have this function that calls itself:

def get_input():
    my_var = input('Enter "a" or "b": ')

    if my_var != "a" and my_var != "b":
        print('You didn\'t type "a" or "b". Try again.')
        get_input()
    else:
        return my_var

print('got input:', get_input())

Now, if I input just "a" or "b", everything works fine:

Type "a" or "b": a
got input: a

But, if I type something else and then "a" or "b", I get this:

Type "a" or "b": purple
You didn't type "a" or "b". Try again.
Type "a" or "b": a
got input: None

I don't know why get_input() is returning None since it should only return my_var. Where is this None coming from and how do I fix my function?

Georgy
  • 12,464
  • 7
  • 65
  • 73
Cate
  • 1,227
  • 2
  • 9
  • 7
  • 18
    You need to do `return Dat_Function()` when calling it recursively. – Gustav Larsson Jul 22 '13 at 00:31
  • 8
    Just a tip: The idiomatic way of that `my_var != "a" and my_var != "b"` condition would be `my_var not in ('a', 'b')` – gonz May 18 '16 at 01:04
  • 1
    @gonz not necessarily. Now you're hitting the heap allocating a tuple just to do a simple comparison. Could be painful in a critical path and it's not much more readable, really. – ggorlen Apr 29 '21 at 01:05
  • 2
    This is a simple example of recursion for demonstration purposes; but in case you actually need to do this task, a `while` loop makes more sense. See [Asking the user for input until they give a valid response](/q/23294658/). – Karl Knechtel Aug 12 '22 at 23:39
  • Sometimes, people run into this problem when trying to *combine iteration and recursion*. If you have a recursive call inside a loop, it might not be clear what to do with the result - since `return` would break out of the loop. In general, however, this is **the same** problem as if you were trying to call **any other** function, rather than using recursion. It is also a commonly asked quesiton, with a reference duplicate here: [How can I use `return` to get back multiple values from a loop? Can I put them in a list?](/questions/44564414) – Karl Knechtel Dec 02 '22 at 12:04

4 Answers4

141

It is returning None because when you recursively call it:

if my_var != "a" and my_var != "b":
    print('You didn\'t type "a" or "b". Try again.')
    get_input()

..you don't return the value.

So while the recursion does happen, the return value gets discarded, and then you fall off the end of the function. Falling off the end of the function means that python implicitly returns None, just like this:

>>> def f(x):
...     pass
>>> print(f(20))
None

So, instead of just calling get_input() in your if statement, you need to return what the recursive call returns:

if my_var != "a" and my_var != "b":
    print('You didn\'t type "a" or "b". Try again.')
    return get_input()
user2357112
  • 260,549
  • 28
  • 431
  • 505
roippi
  • 25,533
  • 4
  • 48
  • 73
  • Shouldn't it run through the if statement again if it is called recursively? I don't understand why it wouldn't return a value. – Cate Jul 22 '13 at 00:35
  • 1
    Nope. See my edit. The recursion happens, and then you discard what the recursion returns. – roippi Jul 22 '13 at 00:38
  • So if you call a function from inside that same function the return value gets discarded, but you return the same function in that function you really just call it in `main()`? – Cate Jul 22 '13 at 00:49
  • 1
    You lost me with that `main()` bit... You can fail as many times as you want to, the one that "succeeds" will return `my_var`, which will get passed down (`return`ed) through all of the recursive calls all the way down to the original caller. Which, yes, is `main()`. – roippi Jul 22 '13 at 00:54
  • I was thinking that when you `return Dat_Function()` you're really just calling `Dat_Function()` again in `main()`. `Dat_Function()` now returns a function and `main()` has go call it. – Cate Jul 22 '13 at 00:58
  • 3
    Use return for recursive function in order to put its value into the stack , so that when function will do recursion values from the stack are taken one by one. If you don't use return , the stack will collect only "None" values. – Baimyrza Shamyr Apr 23 '16 at 18:59
  • 1
    you, sir, are a genius! That was not intuitive to me. – jouell Jun 11 '19 at 14:38
13

To return a value other than None, you need to use a return statement.

In your case, the if block only executes a return when executing one branch. Either move the return outside of the if/else block, or have returns in both options.

Simon
  • 131
  • 2
  • I've tried moving it out of the block, but to no avail. Instead of returning the correct value, it returns the first incorrect value. Also, I don't want a return statement for the if part of the if/else statement because I want the function to only return a correct value. – Cate Jul 22 '13 at 00:39
  • This language "feature" tripped me up for days. As a functional programmer I find it very counterintuitive – ocramz Jul 15 '23 at 08:37
2
def get_input():
    my_var = input('Enter "a" or "b": ')

    if my_var != "a" and my_var != "b":
        print('You didn\'t type "a" or "b". Try again.')
        return get_input()
    else:
        return my_var

print('got input:', get_input())
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
0

I think to understand more what actually going on in your recursive function you should try to debug your code. There is interesting visualizing code execution tool that I recommend called Python Turor.

I will try this test case on your recursive function and visualize the execution process:

First input my_var as x then enter my_var as a.

You can see from the debugging visualizer that when my_var = a it will execute the return statement.

enter image description here

Then the recursive function will return the input value a at this line of code in the recursive function.

enter image description here

After that it will go to execute get_input() function again which it doesn't return any value that's the reason the final value of print('got input:', get_input()) is None.

enter image description here

If your replace get_input() call inside recursive function with return get_input() It will return my_var value which is a in this test case.

enter image description here

Hope this demonstration using Python Tutor debugging visualization tool would be helpful in clarifying the execution process of recursive function.

Oghli
  • 2,200
  • 1
  • 15
  • 37