Python: variable bindings in recursive functions

I stumbled upon some oddity in Python using a function similar to the following:

    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

      

If I enter, for example: "1" then "2" then "3" then "4" I get the following printout:

Good Job! 4 was right
2

      

This is confusing as the function seems to successfully identify the correct answer, but then returns the value that was the second answer instead of the most recent answer.

Can anyone explain what is going on with the "x" binding in this recursive function?

+3


source to share


3 answers


We'll see!

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

      

Inside your foo, you get this:

# 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

      

Since the return value is main (from the outermost recursion) 2

, that's what value

remains.



To fix this, you can make it iterative:

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

      

Or make EACH recursion return the result of a new function

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

      

+4


source


So mainly because you are missing return

in

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

      

What happens is it calls foo(1)

which is not 4, assigns x

equal to 2 and this is the last value that is assigned x

, so

  • Recursive foo(x)

    returns a value, but it is not attached to anything and is not returned from the recursive call.
  • The last value obtained x

    was 2, so the initial one foo(1)

    returns

So either



x = foo(x)

      

or

return foo(x)

      

On the highlighted line

+3


source


Try using the following code:

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

      

You might think that every call to foo creates a new variable x. Thus, recursive calls form a sequence of variables x1, x2, x3, etc. This way, when the function call returns, your local variable x is not changed. This is why you are still getting 2 instead of the assignment from the last recursive call (4). If you want to change a variable passed to a function, you need to pass it by reference (or object), not by value. [Cm. See this article for more details: http://uvesway.wordpress.com/2013/02/18/passing-arguments-to-a-function-by-value-by-reference-by-object/]

+2


source







All Articles