Python Exception Handling & Iterators: Errors & Custom Iterators at Williams College, Slides of Programming Languages

This document from williams college covers python exception handling and custom iterators. It explains how exceptions are handled in python using try/except blocks and the importance of catching only what you can handle. The document also discusses the use of the stopiteration class to signal the end of iteration. Additionally, it provides an example of creating a custom iterator for even squares.

Typology: Slides

2021/2022

Uploaded on 09/27/2022

eknathia
eknathia 🇺🇸

4.4

(26)

264 documents

1 / 4

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Williams College Lecture 24 Brent Heeringa, Bill Jannen
Errors and Exceptions
By now you’ve probably seen your fair share of Python errors. For example:
>>> l = list(range(10))
>>> l[10]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
This IndexError is a Python Exception, which is a way of signaling behavior that is exceptional including
errors. Most modern programming languages support exceptions—they allow you to structure your programs so that
code to both check and deal with errors is logically distinct from your actual control flow. This makes code much
more readable. Here is how exception-handling in Python works. We embed code in a try/except block where,
if an exception is raised, the flow immediately jumps to the except clause. If the type of exception matches, then
the block is entered. Control flow then returns to the code after the except block. For example, running the follow
code
1 l = list(range(10))
2try:
3 l[10]
4except IndexError as ie:
5print(”Caught an IndexError: {} −− moving on”.format(ie))
6
7print(l[0])
produces
Caught an IndexError: list index out of range -- moving on
0
You can use the class hierarchy to catch some types of errors and let others through. For example, above we
would only catch exceptions of type IndexError—if we executed the following code
1 l = list(range(10))
2try:
3 l.push(5)
4except IndexError as ie:
5print(”Caught an IndexError: {} −− moving on”.format(ie))
then the exception would not be caught
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: ’list’ object has no attribute ’push’
Fall Semester 2016 1 CS 135: Diving into the Deluge of Data
pf3
pf4

Partial preview of the text

Download Python Exception Handling & Iterators: Errors & Custom Iterators at Williams College and more Slides Programming Languages in PDF only on Docsity!

Errors and Exceptions

By now you’ve probably seen your fair share of Python errors. For example:

l = list(range(10)) l[10] Traceback (most recent call last): File "", line 1, in IndexError: list index out of range

This IndexError is a Python Exception, which is a way of signaling behavior that is exceptional including errors. Most modern programming languages support exceptions—they allow you to structure your programs so that code to both check and deal with errors is logically distinct from your actual control flow. This makes code much more readable. Here is how exception-handling in Python works. We embed code in a try/except block where, if an exception is raised, the flow immediately jumps to the except clause. If the type of exception matches, then the block is entered. Control flow then returns to the code after the except block. For example, running the follow code

1 l = list(range(10)) 2 try: 3 l[10] 4 except IndexError as ie: 5 print(”Caught an IndexError: {} −− moving on”.format(ie)) 6 7 print(l[0])

produces

Caught an IndexError: list index out of range -- moving on 0

You can use the class hierarchy to catch some types of errors and let others through. For example, above we would only catch exceptions of type IndexError—if we executed the following code

1 l = list(range(10)) 2 try: 3 l.push(5) 4 except IndexError as ie: 5 print(”Caught an IndexError: {} −− moving on”.format(ie))

then the exception would not be caught

Traceback (most recent call last): File "", line 2, in AttributeError: ’list’ object has no attribute ’push’

Errors are actually a good thing: when it comes to exceptions, the rule of thumb is to catch only what you can handle. Consider the portion of the Exception class hierarchy and code example shown below:

BaseException

KeyboardInterrupt Exception

ArithmeticError TypeError

ZeroDivisionError

1 def int fraction(num, denom): 2 try: 3 return num // denom 4 except Exception as e: 5 print(”Can’t divide by zero”) 6 return None

The only exceptional behavior that we can reason about here is dividing-by-zero. However, our except clause catches all exception classes that inherit from the general Exception class. As a result, we do not properly handle the following code:

int_fraction(3, ’a’): Can’t divide by zero None

What we really want is to receive the following error so we know to go back and fix our code:

Traceback (most recent call last): File ‘‘’’, line 1, in TypeError: unsupported operand type(s) for //: ’int’ and ’str’

We would simply change our except clause to catch the specific ZeroDivisionError class.

1 def int fraction(num, denom): 2 try: 3 return num // denom 4 except ZeroDivisionError as e: 5 print(”Can’t divide by zero −− returning 0”) 6 return 0

To cause an error, you simply raise the name of a class that is derived from BaseException. In the next section on iterators, we’ll see how the built-in StopIteration class is used to signal the end of iteration.

Example: Even Squares

Imagine that you wanted to create an iterator that returned squares that were even. One way to do this is to create a new even squares class that inherits from squares. Without any new methods, the even squares class inherits the behavior of squares as is. However, when next is called, we only want even squares returned. To do this, we override the the next method so that it calls the next method of its superclass until it reaches an even square.

1 class EvenSquares(Squares): 2 3 def next (self): 4 sq = super(). next () 5 while (sq % 2 != 0): 6 sq = super(). next () 7 return sq