Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Python Python Basics Functions and Looping Raising Exceptions

Lawrence Grifa
Lawrence Grifa
4,243 Points

raising exceptions and using "as" in Python

How exactly did Craig get rid of the traceback error message and replace it with a nice clean message... Cheers guys :)

2 Answers

Louise St. Germain
Louise St. Germain
19,424 Points

Hi Lawrence,

When he was originally getting the traceback, it was because the code that was going to generate an exception (which was the split_check function) was not inside the try block:

try:
    total_due = float(input("What is the total? "))
    number_of_people = int(input("How many people? "))
except ValueError:
    print("Oh no! That's not a valid value. Try again...")
else:
    # This next line is the one that will cause the ValueError,
    # but it's not inside the try block where it can be caught...
    amount_due = split_check(total_due, number_of_people)
    print("Each person owes ${}".format(amount_due))

So Craig moved the line where it calls split_check into the try block, like this:

try:
    total_due = float(input("What is the total? "))
    number_of_people = int(input("How many people? "))
    # Now, exceptions from this next line will also be caught.
    amount_due = split_check(total_due, number_of_people)
except ValueError:
    print("Oh no! That's not a valid value. Try again...")
else:
    print("Each person owes ${}".format(amount_due))

That way, if there's a ValueError from split_check, it's caught and instead of printing out a nasty traceback and causing the whole program to die, it runs the code in the except block. In our case, this prints out a nice little note. However, even though the ValueError from split_check has been configured to send back a customized message, our current code doesn't have a way to grab that message and display it to the user - so it disappears into a black hole.

So next Craig updates the code to grab that message from the ValueError, which is what that as err part of the code is: it assigns the message that came with the ValueError to a variable called err, which you can then use later to display it, like this:

try:
    total_due = float(input("What is the total? "))
    number_of_people = int(input("How many people? "))
    amount_due = split_check(total_due, number_of_people)
except ValueError as err:  # Now we have a variable called err that will contain the error msg
    print("Oh no! That's not a valid value. Try again...")
    print("({})".format(err)) # This prints out the error msg from the ValueError
else:
    print("Each person owes ${}".format(amount_due))

Anyway, I hope some of this helps. If you're still unsure about any of this, or if I misunderstood your question, let me know!

Lawrence Grifa
Lawrence Grifa
4,243 Points

Thank you so much thats great

Hi Lawrence,

Thank you for your explanation. I sort of understand it, but not completely. I think i am getting confused with the order the lines of code are being run.

This code is before the split_check call got transfered into the try block.

(1) def split_check(total, number_of_people):
(2)   if number_of_people <= 1:
(3)        raise ValueError("more than 1 person is required to split the check")
(4) return math.ceil(total/number_of_people)

(5) try:
(6)   total_due = float(input("What is the total?   "))
(7)    number_of_people = int(input("How many people?   "))

(8) except ValueError:
(9)   print "oh no! Thats not a valid value.Try again...")

(10) else:
(11)   amount_due = split_check(total_due, number_of_people)
(12)   print("Each person owes ${}".format(amount_due))

this is how i think order of the code ran: (5), (6) , (7), (10),

(11) - it calls the split_check function (2) - The if function catches the error as the number_of_people entered is less than or equal to1. (3) - it raises the value error ("more than 1 person is required to split the check"). END.

However after the split_check function got moved to the try block....

(1) def split_check(total, number_of_people):
(2)   if number_of_people <= 1:
(3)        raise ValueError("more than 1 person is required to split the check")
(4) return math.ceil(total/number_of_people)

(5) try:
(6)   total_due = float(input("What is the total?   "))
(7)    number_of_people = int(input("How many people?   "))
**(8)    amount_due = split_check(total_due, number_of_people)**

(9) except ValueError:
(10)   print "oh no! Thats not a valid value.Try again...")

(11) else:
(13)   print("Each person owes ${}".format(amount_due))

This is how the order of the code should have been run:

(5), (6), (7),(8), (2) the if function picks up the error (3) the value error "more than 1 person is required to split the check" is raised and displayed to the user.

my question is (based on the above order): 1) Why do we need to put the ValueError as err and then to print(err) when based on the above order of operation it should have printed that error message already? 2) How did line (10) run ? because this code would have been skipped.

I hope my question makes sense.