+ All Categories
Home > Documents > Asserts and Error Handling

Asserts and Error Handling

Date post: 16-Oct-2021
Category:
Upload: others
View: 16 times
Download: 0 times
Share this document with a friend
40
Asserts and Error Handling Lecture 11
Transcript
Page 1: Asserts and Error Handling

Asserts and Error Handling

Lecture 11

Page 2: Asserts and Error Handling

Announcements for Today

(Optional) Videos

• Lesson 13, 14 for today• Videos 15.1-15.7 next time

Assignments

• Finishing Assignment 1§ We are going to score it§ Get one more chance Sun.

• Assignment 2 due tonight§ Will grade it this weekend§ Solutions posted on Monday

• Assignment 3 due next week§ Before you leave for break§ Same “length” as A1

9/30/21 Asserts & Error Handling 2

• Prelim, Oct 19th 7:30-9:00§ Material up October 5th§ Study guide next week

• Conflict with Prelim time?§ Submit to Prelim 1 Conflict

assignment on CMS§ Do not submit if no conflict

Page 3: Asserts and Error Handling

Using Color Objects in A3

• New classes in introcs§ RGB, CMYK, and HSL

• Each has its own attributes§ RGB: red, blue, green§ CMYK: cyan, magenta,

yellow, black§ HSL: hue, saturation, light

• Attributes have invariants§ Limits the attribute values§ Example: red is int in 0..255§ Get an error if you violate

>>> import introcs>>> c = introcs.RGB(128,0,0)>>> r = c.red>>> c.red = 500 # out of rangeAssertionError: 500 outside [0,255]

9/30/21 Asserts & Error Handling 3

id1c

128r

id1

red 128

green 0

blue 0

RGB

Page 4: Asserts and Error Handling

>>> import introcs>>> c = introcs.RGB(128,0,0)>>> r = c.red>>> c.red = 500 # out of rangeAssertionError: 500 outside [0,255]

Using Color Objects in A3

• New classes in introcs§ RGB, CMYK, and HSL

• Each has its own attributes§ RGB: red, blue, green§ CMYK: cyan, magenta,

yellow, black§ HSL: hue, saturation, light

• Attributes have invariants§ Limits the attribute values§ Example: red is int in 0..255§ Get an error if you violate

9/30/21 Asserts & Error Handling 4

id1c

128r

id1

red 128

green 0

blue 0

RGB

Constructor function.To make a new color.

AccessingAttribute

Page 5: Asserts and Error Handling

Recall: The Call Stack

• Functions are stacked§ Cannot remove one above

w/o removing one below§ Sometimes draw bottom up

(better fits the metaphor)

• Stack represents memory as a high water mark§ Must have enough to keep the

entire stack in memory§ Error if cannot hold stack

9/30/21 Asserts & Error Handling 5

Frame 1

Frame 2

Frame 3

Frame 4

Frame 6Frame 5

calls

calls

calls

calls

Page 6: Asserts and Error Handling

Error Messages

Not An Error Message

ZeroDivisionError: division by zero

An Error Message

Traceback (most recent call last):File "error.py", line 41, in <module>print(function_1(1,0))

File "error.py", line 16, in function_1return function_2(x,y)

File "error.py", line 26, in function_2return function_3(x,y)

File "error.py", line 36, in function_3return x/y

ZeroDivisionError: division by zero

Everything starting with the Traceback

9/30/21 Asserts & Error Handling 6

Page 7: Asserts and Error Handling

Errors and the Call Stack

# error.py

def function_1(x,y):return function_2(x,y)

def function_2(x,y):return function_3(x,y)

def function_3(x,y):return x/y # crash here

if __name__ == '__main__':print(function_1(1,0))

9/30/21 Asserts & Error Handling 7

calls

calls

calls

Page 8: Asserts and Error Handling

Errors and the Call Stack

# error.py

def function_1(x,y):return function_2(x,y)

def function_2(x,y):return function_3(x,y)

def function_3(x,y):return x/y # crash here

if __name__ == '__main__':print(function_1(1,0))

Crashes produce the call stack:Traceback (most recent call last):File "error.py", line 20, in <module>print(function_1(1,0))

File "error.py", line 8, in function_1return function_2(x,y)

File "error.py", line 12, in function_2return function_3(x,y)

File "error.py", line 16, in function_3return x/y

9/30/21 Asserts & Error Handling 8

Make sure you can see line numbers in Atom.

Page 9: Asserts and Error Handling

Errors and the Call Stack

# error.py

def function_1(x,y):return function_2(x,y)

def function_2(x,y):return function_3(x,y)

def function_3(x,y):return x/y # crash here

if __name__ == '__main__':print function_1(1,0)

9/30/21 Asserts & Error Handling 9

Crashes produce the call stack:Traceback (most recent call last):File "error.py", line 20, in <module>print(function_1(1,0))

File "error.py", line 8, in function_1return function_2(x,y)

File "error.py", line 12, in function_2return function_3(x,y)

File "error.py", line 16, in function_3return x/y

Make sure you can see line numbers in Atom.

Where error occurred (or where was found)

Script code.Global space

Page 10: Asserts and Error Handling

Recall: Assigning Responsibility

FunctionDeveloper 1 Developer 2

Defines Calls

BROKEN

Whose fault is it?Who must fix it?

9/30/21 Asserts & Error Handling 10

Page 11: Asserts and Error Handling

Determining Responsibility

def function_1(x,y):"""Returns: result of function_2

Precondition: x, y numbers"""return function_2(x,y)

def function_2(x,y):"""Returns: x divided by y

Precondition: x, y numbers"""return x/y

print(function_1(1,0))

Traceback (most recent call last):

File "error1.py", line 32, in <module>print(function_1(1,0))

File "error1.py", line 18, in function_1return function_2(x,y)

File "error1.py", line 28, in function_2return x/y

ZeroDivisionError: division by zeroWhere is the error?

9/30/21 Asserts & Error Handling 11

Page 12: Asserts and Error Handling

Approaching the Error Message

• Start from the top• Look at function call

§ Examine arguments§ (Print if you have to)§ Verify preconditions

• Violation? Error found§ Else go to next call§ Continue until bottom

Traceback (most recent call last):

File "error1.py", line 32, in <module>print(function_1(1,0))

File "error1.py", line 18, in function_1return function_2(x,y)

File "error1.py", line 28, in function_2return x/y

ZeroDivisionError: division by zero

9/30/21 Asserts & Error Handling 12

Page 13: Asserts and Error Handling

Determining Responsibility

def function_1(x,y):"""Returns: result of function_2

Precondition: x, y numbers"""return function_2(x,y)

def function_2(x,y):"""Returns: x divided by y

Precondition: x, y numbers"""return x/y

print(function_1(1,0))

Traceback (most recent call last):

File "error1.py", line 32, in <module>print(function_1(1,0))

File "error1.py", line 18, in function_1return function_2(x,y)

File "error1.py", line 28, in function_2return x/y

ZeroDivisionError: division by zeroWhere is the error?

A

B

C

9/30/21 Asserts & Error Handling 13

Page 14: Asserts and Error Handling

Determining Responsibility

def function_1(x,y):"""Returns: result of function_2

Precondition: x, y numbers"""return function_2(x,y)

def function_2(x,y):"""Returns: x divided by y

Precondition: x, y numbers"""return x/y

print(function_1(1,0))

Traceback (most recent call last):

File "error1.py", line 32, in <module>print(function_1(1,0))

File "error1.py", line 18, in function_1return function_2(x,y)

File "error1.py", line 28, in function_2return x/y

ZeroDivisionError: division by zero

Error!

9/30/21 Asserts & Error Handling 14

Page 15: Asserts and Error Handling

Determining Responsibility

def function_1(x,y):"""Returns: result of function_2

Precondition: x, y numbers"""return function_2(x,y)

def function_2(x,y):"""Returns: x divided by y

Precondition: x, y numbs, y > 0"""return x/y

print(function_1(1,0))

Traceback (most recent call last):

File "error1.py", line 32, in <module>print(function_1(1,0))

File "error1.py", line 18, in function_1return function_2(x,y)

File "error1.py", line 28, in function_2return x/y

ZeroDivisionError: division by zeroWhere is the error?

A

B

C

9/30/21 Asserts & Error Handling 15

Page 16: Asserts and Error Handling

Determining Responsibility

def function_1(x,y):"""Returns: result of function_2

Precondition: x, y numbers"""return function_2(x,y)

def function_2(x,y):"""Returns: x divided by y

Precondition: x, y numbs, y > 0"""return x/y

print(function_1(1,0))

Traceback (most recent call last):

File "error1.py", line 32, in <module>print(function_1(1,0))

File "error1.py", line 18, in function_1return function_2(x,y)

File "error1.py", line 28, in function_2return x/y

ZeroDivisionError: division by zero

Error!

9/30/21 Asserts & Error Handling 16

Page 17: Asserts and Error Handling

Determining Responsibility

def function_1(x,y):"""Returns: result of function_2

Precondition: x, y numbs, y > 0"""return function_2(x,y)

def function_2(x,y):"""Returns: x divided by y

Precondition: x, y numbs, y > 0"""return x/y

print(function_1(1,0))

Traceback (most recent call last):

File "error1.py", line 32, in <module>print(function_1(1,0))

File "error1.py", line 18, in function_1return function_2(x,y)

File "error1.py", line 28, in function_2return x/y

ZeroDivisionError: division by zero

Error!

9/30/21 Asserts & Error Handling 17

Page 18: Asserts and Error Handling

Aiding the Search Process

• Responsibility is “outside of Python”§ Have to step through the error message§ Compare to specification at each step

• How can we make this easier?§ What if we could control the error messages?§ Write responsibility directly into error?§ Then only need to look at error message

• We do this with assert statements9/30/21 Asserts & Error Handling 18

Page 19: Asserts and Error Handling

Assert Statements

• Form 1: assert <boolean>§ Does nothing if boolean is True§ Creates an error is boolean is False

• Form 2: assert <boolean>, <string> § Very much like form 2§ But error message includes the string

• Statement to verify a fact is true§ Similar to assert_equals used in unit tests § But more versatile with complete stack trace

9/30/21 Asserts & Error Handling 19

Page 20: Asserts and Error Handling

Why Do This?

• Enforce preconditions!§ Put precondition as assert.§ If violate precondition,

the program crashes• Provided code in A3

uses asserts heavily§ First slide of lecture!

def exchange(from_c, to_c, amt)"""Returns: amt from exchange

Precondition: amt a float…"""assert type(amt) == float…

9/30/21 Asserts & Error Handling 20

assert <boolean> # Creates error if <boolean> falseassert <boolean>, <string> # As above, but displays <String>

Will do yourself in A4.

Page 21: Asserts and Error Handling

Example: Anglicizing an Integer

def anglicize(n):"""Returns: the anglicization of int n.

Precondition: n an int, 0 < n < 1,000,000"""assert type(n) == int, repr(n)+' is not an int'assert 0 < n and n < 1000000, repr(n)+' is out of range'# Implement method here…

9/30/21 Asserts & Error Handling 21

Page 22: Asserts and Error Handling

Example: Anglicizing an Integer

def anglicize(n):"""Returns: the anglicization of int n.

Precondition: n an int, 0 < n < 1,000,000"""assert type(n) == int, repr(n)+' is not an int'assert 0 < n and n < 1000000, repr(n)+' is out of range'# Implement method here…

9/30/21 Asserts & Error Handling 22

Check (part of)the precondition

Error message when violated

Page 23: Asserts and Error Handling

Aside: Using repr Instead of str

>>> msg = str(var)+' is invalid'>>> print(msg)2 is invalid

• Looking at this output, what is the type of var?

9/30/21 Asserts & Error Handling 23

A: intB: floatC: strD: Impossible to tell

Page 24: Asserts and Error Handling

Aside: Using repr Instead of str

>>> msg = str(var)+' is invalid'>>> print(msg)2 is invalid

• Looking at this output, what is the type of var?

9/30/21 Asserts & Error Handling 24

A: intB: floatC: strD: Impossible to tell CORRECT

Page 25: Asserts and Error Handling

Aside: Using repr Instead of str

>>> msg = str(var)+' is invalid'>>> print(msg)2 is invalid

>>> msg = repr(var)+' is invalid'>>> print(msg)'2' is invalid

9/30/21 Asserts & Error Handling 25

Clear that varis really a string

Page 26: Asserts and Error Handling

Enforcing Preconditions is Tricky!

def lookup_netid(nid):"""Returns: name of student with netid nid.

Precondition: nid is a string, which consists of 2 or 3 letters and a number"""assert ?????

9/30/21 Asserts & Error Handling 26

Assert use expressions only.Cannot use if-statements.

Each one must fit on one line.

Sometimes we will only enforce part of

the precondition

Page 27: Asserts and Error Handling

Enforcing Preconditions is Tricky!

def lookup_netid(nid):"""Returns: name of student with netid nid.

Precondition: nid is a string, which consists of 2 or 3 letters and a number"""assert type(nid) == str, repr(nid) + ' is not a string'assert nid.isalnum(), nid+' is not just letters/digits'

9/30/21 Asserts & Error Handling 27

Returns True if s contains only letters, numbers.

Does this catchall violations?

Page 28: Asserts and Error Handling

Using Functions to Enforce Preconditions

def exchange(src, dst, amt):"""Returns: amount of src received.Precondition: src is a valid currency codePrecondition: dst is a valid currency codePrecondition: amt is a float"""

assert ??????, repr(src) + ' not valid'assert ??????, repr(dst) + ' not valid'assert type(amt)==float, repr(amt)+' not a float'

9/30/21 Asserts & Error Handling 28

Page 29: Asserts and Error Handling

Using Functions to Enforce Preconditions

def exchange(src, dst, amt):"""Returns: amount of src received.Precondition: src is a valid currency codePrecondition: dst is a valid currency codePrecondition: amt is a float"""

assert is_currency(src), repr(src) + ' not valid'assert is_currency(dst), repr(dst) + ' not valid'assert type(amt)==float, repr(amt)+' not a float'

9/30/21 Asserts & Error Handling 29

Page 30: Asserts and Error Handling

Recovering from Errors

• Suppose we have this code:result = input('Number: ') # get number from userx = float(result) # convert string to floatprint('The next number is '+str(x+1))

• What if user mistypes?Number: 12aTraceback (most recent call last):File "prompt.py", line 13, in <module>x = float(result)

ValueError: could not convert string to float: '12a'9/30/21 Asserts & Error Handling 30

Page 31: Asserts and Error Handling

Ideally Would Handle with Conditional

result = input('Number: ') # get number from userif isfloat(result):

x = float(result) # convert to floatprint('The next number is '+str(x+1))

else:print('That is not a number!')

Does not Exist

9/30/21 Asserts & Error Handling 31

Page 32: Asserts and Error Handling

Using Try-Except

try:result = input('Number: ') # get numberx = float(result) # convert to floatprint('The next number is '+str(x+1))

except:print('That is not a number!')

Similar to if-else§ But always does the try block§ Might not do all of the try block

9/30/21 Asserts & Error Handling 32

Page 33: Asserts and Error Handling

Using Try-Except

try:result = input('Number: ') # get numberx = float(result) # convert to floatprint('The next number is '+str(x+1))

except:print('That is not a number!')

Similar to if-else§ But always does the try block§ Might not do all of the try block

9/30/21 Asserts & Error Handling 33

Conversion may crash!

Execute if crashes

Page 34: Asserts and Error Handling

Try-Except is Very Versatile

def isfloat(s):"""Returns: True if string s represents a float"""try:

x = float(s)return True

except:return False

9/30/21 Asserts & Error Handling 34

Conversion to a float might fail

If attempt succeeds,string s is a float

Otherwise, it is not

Page 35: Asserts and Error Handling

Try-Except and the Call Stack

# recover.py

def function_1(x,y):try:

return function_2(x,y)except:

return float('inf')

def function_2(x,y):return function_3(x,y)

def function_3(x,y):return x/y # crash here

• Error “pops” frames off stack§ Starts from the stack bottom§ Continues until it sees that

current line is in a try-block§ Jumps to except, and then

proceeds as if no error

9/30/21 Asserts & Error Handling 35

function_1

function_2

function_3pops

popsline in a try

Page 36: Asserts and Error Handling

Try-Except and the Call Stack

# recover.py

def function_1(x,y):try:

return function_2(x,y)except:

return float('inf')

def function_2(x,y):return function_3(x,y)

def function_3(x,y):return x/y # crash here

• Error “pops” frames off stack§ Starts from the stack bottom§ Continues until it sees that

current line is in a try-block§ Jumps to except, and then

proceeds as if no error • Example:

>>> print function_1(1,0)inf>>>

9/30/21 Asserts & Error Handling 36

No traceback!

How to return∞ as a float.

Page 37: Asserts and Error Handling

Tracing Control Flow

def first(x):print('Starting first.')try:

second(x)except:

print('Caught at first')print('Ending first')

def second(x):print('Starting second.')try:

third(x)except:

print('Caught at second')print('Ending second')

def third(x):print('Starting third.')assert x < 1print('Ending third.')

What is the output of first(2)?

9/30/21 Asserts & Error Handling 37

Page 38: Asserts and Error Handling

Tracing Control Flow

def first(x):print('Starting first.')try:

second(x)except:

print('Caught at first')print('Ending first')

def second(x):print('Starting second.')try:

third(x)except:

print('Caught at second')print('Ending second')

def third(x):print('Starting third.')assert x < 1print('Ending third.')

What is the output of first(2)?

9/30/21 Asserts & Error Handling 38

'Starting first.''Starting second.''Starting third.''Caught at second''Ending second''Ending first'

Page 39: Asserts and Error Handling

Tracing Control Flow

def first(x):print('Starting first.')try:

second(x)except:

print('Caught at first')print('Ending first')

def second(x):print('Starting second.')try:

third(x)except:

print('Caught at second')print('Ending second')

def third(x):print('Starting third.')assert x < 1print('Ending third.')

What is the output of first(0)?

9/30/21 Asserts & Error Handling 39

Page 40: Asserts and Error Handling

Tracing Control Flow

def first(x):print('Starting first.')try:

second(x)except:

print('Caught at first')print('Ending first')

def second(x):print('Starting second.')try:

third(x)except:

print('Caught at second')print('Ending second')

def third(x):print('Starting third.')assert x < 1print('Ending third.')

What is the output of first(0)?

9/30/21 Asserts & Error Handling 40

'Starting first.''Starting second.''Starting third.''Ending third''Ending second''Ending first'


Recommended