0

I'm a newbie in Python and I'm trying to do an excersise from Zed Shaw's book. I've tried to find an answer for my question and debug the code on my own but with no success.

I'm getting "local variable referenced before assignement" error but only after looping one of the branches. E.g. when I choose non-integer character in my input (chosen_car = int(input("> "))) the function should start from the beginning and allow me to choose a correct value. But when I choose the correct number after that I get an error. In a shell it look like this:

You're about to start a race.
You should buy a car before you start.
Let's see how much you have in your pocket.
> Check your poocket (hit enter to proceed)
Oh, you have 1 thousands. Let's see what you can buy with it
> Ok
Choose your car:
    1. Race Car 4k
    2. Sedan 2k
    3. Pickup 1k
> w
Don't waste my time, choose a correct number.
Choose your car:
    1. Race Car 4k
    2. Sedan 2k
    3. Pickup 1k
> 3
Congratulations, you bought a Pickup
Traceback (most recent call last):
  File "ex36.py", line 35, in <module>
    choose_a_car()
  File "ex36.py", line 17, in choose_a_car
    if chosen_car >= 0 and chosen_car <= 3:
UnboundLocalError: local variable 'chosen_car' referenced before assignment

Here's the code. I'll be very helpful for your help.

from random import randint
from sys import exit

def choose_a_car():

    # the list of cars [cost, name]
    cars = [[4, "Hidden Super Car"], [4, "Race Car"], [2, "Sedan"], [1, 
    "Pickup"]]

    print(f"Choose your car:\n\t1. {cars[1][1]} {cars[1][0]}k \n\t2. 
    {cars[2][1]} {cars[2][0]}k \n\t3. {cars[3][1]} {cars[3][0]}k")

    try:
        chosen_car = int(input("> "))
    except ValueError:
        print("Don't waste my time, choose a correct number.")
        choose_a_car()

    if chosen_car >= 0 and chosen_car <= 3:
        if cars[chosen_car][0] <= money:
            print(f"Congratulations, you bought a {cars[chosen_car][1]}")
        else:
            print("Unfortunately, you don't have enough money to buy this 
            car")
            choose_a_car()
    else:
        print("There is no such a car")
        choose_a_car()


print("You're about to start a race.")
print("You should buy a car before you start.")
print("Let's see how much you have in your pocket.")
input("> Check your poocket (hit enter to proceed)")
money = int(randint(1,4))
print(f"Oh, you have {money} thousands. Let's see what you can buy with it")
input("> Ok")
choose_a_car()

print("Let's start a race!")
print("1! \n2! \n3! \nSTART!")
4
  • 1
    In questions like yours, a clear understanding of program structure is important. Please format your code. We need to know which statements are in the function and which are not. Commented Feb 20, 2018 at 6:53
  • SO regulars don't recommend Zed's book. See here for a list of better introductions. Commented Feb 20, 2018 at 7:39
  • 2
    Don't use recursion where a loop will do in Python. Commented Feb 20, 2018 at 20:32
  • Thanks for a hint, I've formatted the code to make it more clear. The list of a books is also very useful, I'll definitely use some of them. Commented Feb 20, 2018 at 21:09

4 Answers 4

1
try:
    chosen_car = int(input("> "))
except ValueError:
    print("Don't waste my time, choose a correct number.")
    choose_a_car()

This code snippet uses recursion. Therefore, if the user enters an invalid input, the program enters the except block and calls the function again. And if the user enters a correct number in the second call, the second call terminates successfully and you turn back to the first function call. However, in the first call, chosen_car is not defined because of the invalid input. Therefore the program crashes with the error. Instead of recursion, you can try to use a flag as follows:

myFlag = True
while( myFlag):
    try:
        chosen_car = int(input("> "))
        myFlag = False
    except ValueError:
        print("Don't waste my time, choose a correct number.")

By doing this, if the program crashes in chosen_car = int(input("> ")) line, myFlag is not set to False and the program continues to get inputs from the user.

I have not checked the code, but I suppose that should work.

Sign up to request clarification or add additional context in comments.

1 Comment

It worked - thanks a ton. It also helped to get a bit better understanding of the problem. I thought that after entering invalid input the function in the second call starts from the very beginning and that python doesn't 'remember' the first call. From what you've said I understand that in fact it's the opposite - after entering correct values the program starts proceeding the first call again.
0

Initialise chosen_car by setting it to None before the try statement. You are getting the exception because by the time you get to line 17 that variable has not been initialised.

3 Comments

That now raises TypeError though
It didn't work for me. Now I get a new error at line 19: TypeError: '>=' not supported between instances of 'NoneType' and 'int'. I don't know why is that. By the time program reaches this line new value is assigned to chosen_car variable which is then converted to integer.
A new value isn't assigned. Read about scope.
0

Here is your problem:

try:
    chosen_car = int(input("> "))
except ValueError:
    print("Don't waste my time, choose a correct number.")
    choose_a_car()

if chosen_car >= 0 and chosen_car <= 3:

If this goes into the except, then chosen car won't be defined. I suggest you define it outside of the try, or put the entire thing inside of a while loop instead of recursing with the choose_a_car().

4 Comments

The first solution didn't work for me. I got a new error at line 19: TypeError: '>=' not supported between instances of 'NoneType' and 'int'. I'm not sure why I'm getting it since by the time program reaches line 19 new value should be assigned to chosen_car variable.
Yeah, the first solution wouldn't work. Only the second solution would (which is implemented by the answer you accepted)
Exactly. I'm not sure if I understand why the first one wouldn't work. Is it because Python repeats the first call again after getting a correct value and it remembers the original input?
It doesn't remember the original input because it goes into the except. With the second solution, chosen car would be whatever value you define it as outside of the try, and this case, it is none. Since it can't compare None to 0, it throws an error
0

You could do something like this:

from random import randint


def get_number(msg, minimum, maximum):
    while True:
        try:
            num = int(input(msg))
        except ValueError:
            print("Don't waste my time, choose a correct number.")
        else:
            if num >= minimum and num <= maximum:
                return num


def choose_a_car():

    # the list of cars [cost, name]
    cars = [[4, "Hidden Super Car"], [4, "Race Car"], [2, "Sedan"], [1, "Pickup"]]

    print(f"Choose your car:\n\t1. {cars[1][1]} {cars[1][0]}k \n\t2. {cars[2][1]} {cars[2][0]}k \n\t3. {cars[3][1]} {cars[3][0]}k")

    chosen_car = get_number('> ', minimum=1, maximum=3)

    if cars[chosen_car][0] <= money:
        print(f"Congratulations, you bought a {cars[chosen_car][1]}")
    else:
        print("Unfortunately, you don't have enough money to buy this car")


print("You're about to start a race.")
print("You should buy a car before you start.")
print("Let's see how much you have in your pocket.")
input("> Check your pocket (hit enter to proceed)")
money = int(randint(1,4))
print(f"Oh, you have {money} thousands. Let's see what you can buy with it")
input("> Ok")
choose_a_car()

1 Comment

It worked, thanks for giving a new perspective to the problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.