1

I've been learning Python for about 3 weeks now, so what I'm working on is obviously going to be very simple. I've already written a couple programs that return values for certain calculations, and I have successfully used exceptions within functions in those programs. The program that I'm currently working on is only for the purpose of me getting some more practice writing functions, while loops, and exceptions. Here's what I've got so far:

def factorial(n):
    while n > 0:
        return n * factorial(n-1)
    return 1

    print factorial(n)

def user():
    n = int(raw_input("What number would you like to use?"))
    try:
        factorial(int(n))
    except ValueError:
        print "You must choose a number. Please try again."
        return user()


if __name__ == '__main__':
    user()

I can't figure out why my exception within the user() function doesn't seem to be running. All I get when I run this code is the raw_input "What number would you like to use?". The factorial() function doesn't run, nor do the print or return statements that I've set if there is a ValueError. Can anyone help me figure out why this is (or rather isn't) happening?

Mark S.
  • 29
  • 5
  • You have `int` around `raw_input` which is not inside of the `try` block. Put the `int(raw_input("What number would you like to use?"))` after `try` and `factorial` after the `except` block – dawg Mar 29 '15 at 05:36
  • Also - take a look at [this post](http://stackoverflow.com/questions/23294658/asking-the-user-for-input-until-they-give-a-valid-response) as to why using recursion is a bad idea for repeating input requests.... – Jon Clements Mar 29 '15 at 05:37

3 Answers3

1

Funny enough, all of the code is running! It just isn't showing anything, because the print statement isn't being called! Lets decompose the user function and see what it does.

What the code is doing

n = int(raw_input("What number would you like to use?"))

Convert the string the user types into an integer and store it into the variable (or, if you want to be pythonic-ly correct, the name) n.

try:
    factorial(int(n))

Try to convert n into an integer (again) and send said integer to the factorial function. Note that n here is already an integer! So this will always succeed. Just call the function, nothing more.

except ValueError:
    print "You must choose a number. Please try again."
    return user()

If ValueError is raised, print an error message, then return the value of user.

We don't print anything whether the conversion was successful or not. We just run a single function then exit. What function do we run?

def factorial(n):
    while n > 0:
        return n * factorial(n-1)
    return 1

    print factorial(n)

Note that in this function the code says to print a value after returning a value. Once a function returns, nothing after the return statement is run. The print statement will not be executed! So this function correctly computes the factorial (recursively), and returns it. Nothing else!

This is why your program will seem to do nothing. This function is called, computes, and returns the answer. The returned answer is simply ignored!

What does this mean?

There are three key lines in your code that define why it's doing what it's doing.

  1. You convert the input from the user into an integer and store it in n
    • This will raise ValueError if the user types anything that isn't an integer.
    • Note that this still happens! if you run the code, type b, then press enter, an exception (ValueError) will be raised.
  2. You convert n into an integer and pass it to factorial.
    • Although this is in the try block (as it should be), n is already an integer. This is why your exception code will never run.
  3. Your only print statement (after getting valid input from the user) is inside the factorial function, after the return statement. It will never be executed. This is why nothing is printed.
    • I don't recommend printing the result inside of a recursive function. It can be done, but it is generally better to return the result and print the returned value, outside of the recursive function. (perhaps in the user function, instead of calling factorial(n) printing what it returns would be better!)

I hope that this helped to clarify exactly what is going on with the code, and I hope I was able to answer your question! Happy coding! :D

  • [Python doesn't have variables, it has names](http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables) - the user input is assigned to the name ```n``` . [Facts and myths about Python names and values](http://nedbatchelder.com/text/names.html) – wwii Mar 29 '15 at 08:18
  • @wwii Interesting. I will admit that I wasn't aware of the "name" tidbit, and will keep it in mind for the future. However, the first link says, and I quote: `Although we commonly refer to "variables" even in Python (because it's common terminology), ...`. As much as I agree the 'correct' terminology should be used, as long as the user of the language understands what the terminology means, I feel it doesn't matter what you call it. As Shakespeare said, "A rose by any other name would smell as sweet." (at least I believe that was him.) Still, I added it to my post. It's important to know. – Nerketur Kamachi Mar 29 '15 at 17:33
  • In Python saying that you are putting a value *into* a variable is misleading and can sometimes cause a bit of confusion when manipulating/mutating values. I just wanted to elaborate on your statement - ```store it into the variable``` – wwii Mar 29 '15 at 18:44
  • @wwii it's funny, because the second link you posted (facts and myths) is directly contradicting the first statement you wrote. from ned's article: `Myth: Python has no variables. Some people like to say, "Python has no variables, it has names." This slogan is misleading.` – wim Mar 29 '15 at 22:31
  • @wim. seems i've lead myself onto a slippery slope. The first one is a bit simplistic - but that phrase definitely got stuck in my head. Hopefully I will be more careful how I phrase things in the future. thnx. – wwii Mar 29 '15 at 23:19
1

Here are my comments expanded into an answer.

First, do not print inside the factorial function. Print the value returned from that function:

def factorial(n):
    while n > 0:
        return n * factorial(n-1)
    return 1

>>> factorial(4)
24

Next, wrap the thing that you think will cause the exception in the try part of the block. In this case, the call to int with unknown user input might cause an exception; wrap that in the try -- no more. Finally, do not use recursion for user input. Use a while loop instead:

def user():
    n=None
    while not n:
        user_int=raw_input("What number would you like to use? ")
        try:
            n=int(user_int)
        except ValueError:
            print "You must choose a number. Please try again."

    print factorial(n)   

if __name__ == '__main__':
    user() 
dawg
  • 98,345
  • 23
  • 131
  • 206
0

first of all you have to print the factorial(int(n)) to see the output, And remove int conversion of your input,

here is my modified code:

def factorial(n):
  2     while n > 0:
  3        return n *factorial(n-1)
  4     return 1
  5     print factorial(n)
  6 
  7 
  8 
  9 
 10 def user():
 11     n = raw_input("What number would you like to use?")
 12 
 13     try:
 14 
 15         print factorial(int(n))
 16     except ValueError:
 17         print "You must choose a number. Please try again."
 18         return user()
 19 
 20 if __name__ == '__main__':
 21     user()

hope this helps,

lazarus
  • 677
  • 1
  • 13
  • 27