1 of 46

Lecture 20

Exceptions

2 of 46

Exceptions

3 of 46

Why?

  • An exception is an event, which occurs during the execution of a program that disrupts the normal flow of the program's instructions.
    • A function receives an argument value of an improper type
    • Some resource (such as a file) is not available
    • A network connection is lost in the middle of data transmission

  • In general, when a Python script encounters a situation that it cannot cope with, it raises an exception.
  • An exception is a Python object that represents an error.

4 of 46

Exceptions

  • A built-in mechanism in a programming language to declare and respond to exceptional conditions.
  • Python raises an exception whenever an error occurs
  • Exceptions can be handled by the program, preventing the interpreter from halting (come to an abrupt stop)
  • Unhandled exceptions will cause Python to halt execution and print a stack trace
    • Long message that tells you what line has what error

5 of 46

Raising Exceptions

6 of 46

Raise Statements

Exceptions are raised with a raise statement

<expression> must evaluate to a subclass of BaseException or an instance of one.

Exceptions are constructed like any other object. E.g., TypeError('Bad argument!')

7 of 46

Raise Statements

Exceptions are raised with a raise statement

<expressions> must evaluate to a subclass of BaseException or an instance of one

Exceptions are constructed like any other object. E.g., TypeError('Bad argument!')

8 of 46

Raise Statements

Exceptions are raised with a raise statement

<expressions> must evaluate to a subclass of BaseException or an instance of one

Exceptions are constructed like any other object. E.g., TypeError('Bad argument!')

Demo

9 of 46

Problem

  • Write a function that takes a list of numbers that represents ages, should be over 21, and the list of names, then prints the invitations. If the age is < 21 raises ValueError exception.

10 of 46

Problem

Write a function that takes a list of numbers representing ages. They should be over 21, and the list of names, then prints the invitations.

  • If the age is < 21 raises ValueError exception.

def invites(names, ages):

for i in range(len(ages)):

if (ages[i] < 21):

raise ValueError("Too young to come")

else:

print("{} is above 21. {}, you are invited.".format(ages[i], names[i]))

invites(["Tom", "Mary", "Rosa"], [23, 44, 87])

11 of 46

Problem

  • Write a function that takes a list of numbers that represents ages, should be over 21, and the list of names, then prints the invitations. If the age is < 21 raises ValueError exception.

def invites(names, ages):

for i in range(len(ages)):

if (ages[i] < 21):

raise ValueError("Too young to come")

else:

print("{} is above 21. {}, you are invited.".format(ages[i], names[i]))

invites(["Tom", "Mary", "Rosa"], [23, 44, 87])

23 is above 21. Tom, you are invited.

44 is above 21. Mary, you are invited.

87 is above 21. Rosa, you are invited.

12 of 46

Problem

  • Write a function that takes a list of numbers that represents ages, should be over 21, and the list of names, then prints the invitations. If the age is < 21 raises ValueError exception.

def invites(names, ages):

for i in range(len(ages)):

if (ages[i] < 21):

raise ValueError("Too young to come")

else:

print("{} is above 21. {}, you are invited.".format(ages[i], names[i]))

invites(["Tom", "Mary", "Rosa"], [13, 44, 87])

Traceback (most recent call last):

File "/Users/marinalanglois/Desktop/tt.py", line 9, in <module>

invites(["Tom", "Mary", "Rosa"], [13, 44, 87])

File "/Users/marinalanglois/Desktop/tt.py", line 4, in invites

raise ValueError("Too young to come")

ValueError: Too young to come

13 of 46

Try Statements

14 of 46

Try statements

Try statements handle exceptions

15 of 46

Handling Exceptions

Exception handling can prevent a program from terminating

16 of 46

Handling Exceptions

Exception handling can prevent a program from terminating

17 of 46

Handling Exceptions

Exception handling can prevent a program from terminating

18 of 46

Handling Exceptions

Exception handling can prevent a program from terminating

19 of 46

Handling Exceptions

Exception handling can prevent a program from terminating

20 of 46

Try statements

Try statements handle exceptions

Execution rule:

  • The <try suite> is executed first
  • If, during the course of executing the <try suite>, an exception is raised and
  • the <exception class> is executed, with <name> bound to the exception

21 of 46

Handling Exceptions

Exception handling can prevent a program from terminating

Multiple try statements: Control jumps to the except suite of the most recent try statement that handles that type of exception

22 of 46

WWPD? Demo

23 of 46

WWPD?

A: ZeroDivisionError: division by zero

B: Never printed if x is 0

C: 'division by zero' # str(e)

D: Something else

24 of 46

WWPD?

A: ZeroDivisionError: division by zero

B: Never printed if x is 0

C: 'division by zero' # str(e)

D: Hello!

E: Something else

25 of 46

WWPD?

A: NameError

B: ZeroDivisionError: division by zero

C: Something else, your questions are tricky

26 of 46

Multiple Excepts

try:

You do your operations here;

......................

except ExceptionI:

If there is ExceptionI, then execute this block.

except ExceptionII:

If there is ExceptionII, then execute this block.

......................

else:

If there is no exception then execute this block.

27 of 46

try-except-else

try:

fh = open("testfile", "w")

fh.write("Writing something to the file")

except IOError:

print "Error: file does not exist"

else:

print("Success!")

fh.close()

28 of 46

What is the output?

def handling_invites(names, ages): # does not crash

try:

invites(names, ages)

except ValueError as e:

print(e)

handling_invites(["Tom", "Mary", "Rosa"], [13, 44, 87])

def invites(names, ages):

for i in range(len(ages)):

if (ages[i] < 21):

raise ValueError("Too young to come")

else:

print("{} is above 21. {}, you are invited.".format(ages[i], names[i]))

29 of 46

What is the output?

def handling_invites(names, ages): # does not crash

try:

invites(names, ages)

except ValueError as e:

print(e)

handling_invites(["Tom", "Mary", "Rosa"], [13, 44, 87])

Too young to come

def invites(names, ages):

for i in range(len(ages)):

if (ages[i] < 21):

raise ValueError("Too young to come")

else:

print("{} is above 21. {}, you are invited.".format(ages[i], names[i]))

30 of 46

Output?

def even_better(names, ages):

for i in range(len(ages)):

try:

if (ages[i] < 21):

raise ValueError("Too young to come")

else:

print("{} is above 21. {}, you are invited.".format(ages[i], names[i]))

except ValueError as e:

print("Sorry {}, you are too young".format(names[i]))

even_better(["Tom", "Mary", "Rosa"], [13, 44, 87])

def invites(names, ages):

for i in range(len(ages)):

if (ages[i] < 21):

raise ValueError("Too young to come")

else:

print("{} is above 21. {}, you are invited.".format(ages[i], names[i]))

31 of 46

Output?

def even_better(names, ages):

for i in range(len(ages)):

try:

if (ages[i] < 21):

raise ValueError("Too young to come")

else:

print("{} is above 21. {}, you are invited.".format(ages[i], names[i]))

except ValueError as e:

print("Sorry {}, you are too young".format(names[i]))

>>> even_better(["Tom", "Mary", "Rosa"], [13, 44, 87])

Sorry Tom, you are too young

44 is above 21. Mary, you are invited.

87 is above 21. Rosa, you are invited.

def invites(names, ages):

for i in range(len(ages)):

if (ages[i] < 21):

raise ValueError("Too young to come")

else:

print("{} is above 21. {}, you are invited.".format(ages[i], names[i]))

32 of 46

Split the work

def invites(name, age): # you wrote this function

if (age < 21):

raise ValueError("Too young to come")

else:

print("{} is above 21. {}, you are invited.".format(age, name))

def even_better(names, ages): # I use your function

for i in range(len(ages)):

try:

invites(names[i], ages[i])

except ValueError as e:

print("Sorry {}, you are too young".format(names[i]))

even_better(["Tom", "Mary", "Rosa"], [13, 44, 87])

33 of 46

More examples

>>> x = 17 + “Marina”

34 of 46

More

>>> x = 17 + “Marina”

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

TypeError: unsupported operand type(s) for +: 'int' and 'str'

35 of 46

Do not do it, although Python allows you to

try:

x = 17 + "Marina"

except:

print("Oouch")

Oouch

36 of 46

Pass: ignore and move on

try:

x = 17 + "Marina"

except:

pass

(cont.code from here)

Nothing will happen and the code resumes its execution from (cont. from here)

37 of 46

Pass: ignore and move on

try:

x = 17 + "Marina"

except:

pass

Nothing will happen

Can be used with for/while loops as well

38 of 46

Difference between pass and continue

Pass is just a placeholder. When you use the 'pass' statement, nothing occurs, but it stops errors when you can't have an empty code.

39 of 46

What do you think will happen?

try:

a = 1/0

except NameError as e:

print("printed error")

A: printed error

B: infinity

C: ZeroDivisionError: division by zero

D: ZeroDivisionError: division by zero AND printed error

E: Something else

40 of 46

Difference between assert and exception

  • try/except blocks let you catch and manage exceptions. Exceptions can be triggered by raise, assert, and a large number of errors such as trying to index an empty list. raise is typically used when you have detected an error condition.
  • raise and assert have a different philosophy. There are many "normal" errors in code that you detect and raise errors on. Perhaps a web site doesn't exist or a parameter value is out of range.
  • Assertions are generally reserved for "I swear this cannot happen" issues that seem to happen anyway. It’s more like runtime debugging than normal runtime error detection. Assertions can be disabled if you use the -O flag or run from .pyo files instead of .pyc files, so they should not be part of regular error detection.
  • If production quality code raises an exception, then figure out what you did wrong. If it raises an AssertionError, you've got a bigger problem.

https://stackoverflow.com/questions/40182944/difference-between-raise-try-and-assert

41 of 46

Quick recap about exceptions

  • Exception: is an event, which occurs during the execution of a program that disrupts the normal flow of the program's instructions.
  • Can occur due to different issues: syntax errors or runtime errors
  • How to handle an exception?
    • Use try … except block
    • Example:

>>> try:

... {}["name"]

... except KeyError as e:

... print("bad key!")

42 of 46

Quick recap about exceptions

  • Exception: is an event, which occurs during the execution of a program that disrupts the normal flow of the program's instructions.
  • Can occur due to different issues: syntax errors or runtime errors
  • How to handle an exception?
    • Use try … except block
    • Example:

>>> try:

... {}["name"]

... except KeyError as e:

... print("bad key!")

bad key!

43 of 46

Quick recap about exceptions

  • Exception: is an event, which occurs during the execution of a program that disrupts the normal flow of the program's instructions.
  • Can occur due to different issues: syntax errors or runtime errors
  • How to handle an exception?
    • Use try … except block
    • Example:

try:

{}["name"]

except KeyError as e:

print("bad key!")

lst = [3, 4, 5]

lst.append(6)

print(lst)

bad key!

[3, 4, 5, 6]

44 of 46

Quick recap: your code can raise exceptions too

  • Exceptions are raised with a raise statement
  • Example:

def sum_them(dict1, dict2):

# same keys, at least one even key

# add values for only even keys

"""

>>> dict1 = {1:1, 2:2}

>>> dict2 = {1:-1, 2: -2}

>>> sum_them(dict1, dict2)

{2:0}

"""

output = {}

for key in dict1:

if key%2==0:

output[key] = dict1[key] + dict2[key]

return output

45 of 46

Quick recap: your code can raise exceptions too

  • Exceptions are raised with a raise statement
  • Example:

def sum_them(dict1, dict2):

# same keys, at least one even key

# add values for only even keys

output = {}

for key in dict1:

if key%2==0:

output[key] = dict1[key] + dict2[key]

if len(output)==0:

raise KeyError("Must be at least one even key")

return output

46 of 46

Another function can handle it

def sum_them(dict1, dict2):

output = {}

for key in dict1:

if key%2==0:

output[key] = dict1[key] + dict2[key]

if len(output)==0:

raise KeyError("Must be at least one even key")

return output

def many_sums_v1(*args):

lst = []

first_list = args[0::2]

second_list = args[1::2]

combined=list(zip(first_list, second_list))

try:

for item in combined:

lst.append(sum_them(*item))

except KeyError:

lst.append({0:0})

return lst