0% found this document useful (0 votes)
48 views43 pages

CMPUT 175 Lecture #5

Invalid index Identifier not defined End of program

Uploaded by

deep81204
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
48 views43 pages

CMPUT 175 Lecture #5

Invalid index Identifier not defined End of program

Uploaded by

deep81204
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 43

CMPUT 175

Introduction to Foundations
of Computing
Exceptions and handling Errors

You should view the vignettes:


Call Stack
Handling Exceptions
Exceptions Metaphor
Post-test

February 7, 2024 © Osmar R. Zaïane : University of Alberta 1


Objectives
In this lecture we will learn how to use
Python Exceptions to handle unusual
program conditions.

February 7, 2024 © Osmar R. Zaïane : University of Alberta 2


Outline
When things go wrong
Exceptions
Catching exceptions
Raising exceptions
Defining your own exception classes
Assertions

February 7, 2024 © Osmar R. Zaïane : University of Alberta 3


When things go wrong…
We have talked about input validation.
It is good practice to always check the
input a user provides to make sure it is
what is expected in terms of type, value
interval, etc. This avoids unexpected
errors. But errors can still happen.

Programs must be able to handle


unusual situations and manage
appropriately when things go wrong.
February 7, 2024 © Osmar R. Zaïane : University of Alberta 4
Reacting to errors

What if
the user enters a string instead of an integer?
We try to pop an empty stack?
we try to divide by zero?
We try to read from a file which doesn’t exist?
We try to access a remote location but the network is
down?

Should the program produce bad output, or


should it crash, or should it try to recover?
February 7, 2024 © Osmar R. Zaïane : University of Alberta 5
Handling Unusual
Situations
In many languages, the programmer is responsible for
dealing with errors – no help from the language itself

Code must be written to help identify kinds of errors and


how to deal with them – convoluted code!

Often, methods will return an unusual value such as


–1 or null to indicate a failure – often difficult to
interpret! [A common practice with C/C++]

Python provides some helpful mechanisms to assist us by


handling exceptions.
February 7, 2024 © Osmar R. Zaïane : University of Alberta 6
What is an Exception?

An exception is an event, which occurs during the


execution of a program, that disrupts the normal
flow of the program's instructions.
Exceptions are a means of breaking out of the
normal flow of control of a code block in order to
handle errors or other exceptional conditions.
An exception is a Python object that represents an
error.

February 7, 2024 © Osmar R. Zaïane : University of Alberta 7


What is an Exception?
How do we recover from errors, or at least
handle them gracefully?
In general, when a Python script encounters a
situation that it can't cope with, it raises an
exception at the point where the error is
detected.
The Python interpreter raises an exception when
it detects a run-time error.
A Python program can also explicitly raise an
exception.
February 7, 2024 © Osmar R. Zaïane : University of Alberta 8
Python interpreter and Exceptions
>>> '2023' + 1
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: cannot concatenate 'str' and 'int' objects
>>> 175 + cmput*13
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'cmput' is not defined
>>> 365 * (12/0)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
February 7, 2024 © Osmar R. Zaïane : University of Alberta 9
Other typical exceptions
Accessing a non-existent dictionary key
will raise a KeyError exception.
Searching a list for a non-existent value
will raise a ValueError exception.
Calling a non-existent method
will raise an AttributeError exception.
Referencing a non-existent variable
will raise a NameError exception.
Mixing datatypes without coercion
will raise a TypeError exception.
February 7, 2024 © Osmar R. Zaïane : University of Alberta 10
Why use exceptions?

The advantages of using exceptions include:


separating error-handling code from regular
code
deferring decisions about how to respond to
exceptions
providing a mechanism for specifying the
different kinds of exceptions that can arise in
our program

February 7, 2024 © Osmar R. Zaïane : University of Alberta 11


The Exception handling
blocks
If you have some suspicious code that may raise an
exception, you can defend your program by placing the
suspicious code in a try: block. After the try: block, include
an except: statement, followed by a block of code which
handles the problem
try:
f = open('myfile.txt')
except IOError :
print("I/O error: File does not exist or cannot be read.")
Once an exception has been handled, processing continues
normally on the first line after the try...except block.

February 7, 2024 © Osmar R. Zaïane : University of Alberta 12


Catching Exceptions
if you don't catch the exception, your entire
program will crash
except Exception1: catches Exception 1
An except clause may name multiple
exceptions as a parenthesized tuple, for
example:
except (RuntimeError, TypeError, NameError):

An except clause without explicit exception


will catch all remaining exception
try:
some statements
except: print("Unexpected error:")
February 7, 2024 © Osmar R. Zaïane : University of Alberta 13
Multiple except clauses
A try statement may have more than one except
clause, to specify handlers for different exceptions. At
most one handler will be executed. Handlers only
handle exceptions that occur in the corresponding try
clause, not in other handlers of the
same try statement.
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except IOError :
print ("I/O error: File does not exist or cannot be read.")
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:")
February 7, 2024 © Osmar R. Zaïane : University of Alberta 14
The try statement
The try statement works as follows.
1. The try clause (the statement(s) between
the try and except keywords) is executed.
2. If no exception occurs, the except clause is skipped and
execution of the try statement is finished.
3. If an exception occurs during execution of the try clause,
the rest of the clause is skipped. Then if its type matches
the exception named after the except keyword, the
except clause is executed, and then execution continues
after the try statement.
4. If an exception occurs which does not match the
exception named in the except clause, it is passed on to
outer try statements; if no handler is found, it is
an unhandled exception and execution stops with a
message.
February 7, 2024 © Osmar R. Zaïane : University of Alberta 15
Exception handling
When we write a piece of code that we know might
produce an exception and we want to handle the
exception, we encapsulate that code in a try…except
block.
If no exception is raised by the code within the try block
(or the methods that are called within the try block), the
code executes normally.

If an exception arises in the try block the execution of the


try block terminates execution immediately and an except
is sought to handle the exception. Either
1. An appropriate except clause is found, in which case it is
executed, or
2. The exception is propagated to the calling method
February 7, 2024 © Osmar R. Zaïane : University of Alberta 16
What is the output ?
Invalid index Invalid index
try: try:
alist = 5 * [0] alist = 5 * [s]
last_item = alist[len(alist)] last_item = alist[len(alist)]
print('Done') print('Done')
except IndexError: except (IndexError,NameError):
print('Invalid index') print('Invalid index')

Identifier not defined


try: End of program try:
alist = 5 * [s]
alist = 5 * [s]
last_item = alist[len(alist)]
last_item = alist[len(alist)]
print('Done')
print('Done')
except IndexError:
except ValueError:
print('Invalid index')
print('Incorrect Value')
except NameError:
print('End of program')
print('Identifier not defined')
print('End of program') Traceback (most recent call last):
Python Shell, prompt 3, line 2
February 7, 2024 builtins.NameError:
© Osmar R. Zaïane : University of Alberta name 's' is not defined
17
What is the output ?
Denominator is zero def main(): Some error
def main():
try:
try:
foo()
foo()
print('After function call')
print('After function call')
except ZeroDivisionError:
except ZeroDivisionError:
print('Denominator is zero')
print('Denominator is zero')
except:
except:
print('Some error')
print('Some error')
def foo():
def foo():
print([ ][0])
print(1/0)
main()
main()

The except clause without the Exception Name is a default clause.


It is always specified after all except clauses have been specified.
February 7, 2024 © Osmar R. Zaïane : University of Alberta 18
Propagating exceptions

An exception will bubble up the call stack


until
it reaches a method with a suitable handler, or
it propagates through the main program (the
first method on the call stack)

If it is not caught by any method the


exception is treated like an error: the stack
frames are displayed and the program
terminates
February 7, 2024 © Osmar R. Zaïane : University of Alberta 19
Example of propagation of Exception
to Caller - What is the output ?
def main(): # CALLER Exception handled in main
try: A string object is immutable
foo()
print('After function call')
except TypeError: # Exception CAUGHT IN MAIN
print('Exception handled in main')
print('A string object is immutable')
except:
print('Some error occurred')

def foo(): # CALLEE


try:
astring = 'hello'
astring[0] = 'j'
except NameError: # Exception not caught-propagated to CALLER
print('Incorrect Name')
main()
February 7, 2024 © Osmar R. Zaïane : University of Alberta 20
Handling and Propagating
by Raising Exception
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except IOError :
print ("I/O error: File does not exist or cannot be read.")
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:")
raise

February 7, 2024 © Osmar R. Zaïane : University of Alberta 21


Raising Exception To Caller -1
Exception handled in main
def main(): A string object is immutable
try:
foo()
print('After function call')
except TypeError: # Exception CAUGHT AND HANDLED IN CALLER
print('Exception handled in main - A string object is immutable')
except:
print('Some error occurred')

def foo():
try:
astring = 'hello'
astring[0] = 'j'
except TypeError:
raise # Using raise will raise the exception caught in the exception clause
main()

February 7, 2024 © Osmar R. Zaïane : University of Alberta 22


Using raise - What is the
output ? Index Error in main
def main(): Index Error in foo def main():
try: After function call try:
foo() foo()
print('After function call') print('After function call')
except ZeroDivisionError: except ZeroDivisionError:
print('Denominator is zero’) print('Denominator is zero’)
except IndexError: except IndexError:
print('Index Error in main') print('Index Error in main')
except: except:
print('Some error') print('Some error')

def foo(): def foo():


try: try:
print([ ][0]) print([ ][0])
except IndexError: except IndexError:
print('Index Error in foo') raise
main()
February 7, 2024 main()
© Osmar R. Zaïane : University of Alberta 23
Using Exception Objects
An exception can have an argument, which is a value
that gives additional information about the problem. The
contents of the argument vary by exception.
try:
some statements
except ExceptionType as instance:
You can print value of Argument here using the args property
of the instance of the exception. args is a tuple

This argument receives the value of the exception


mostly containing the cause of the exception.
def prn_convert(var): >>> prn_convert("CMPUT")
try: The argument does not contain numbers
print (int(var)) ("invalid literal for int() with base 10: 'CMPUT'",)
except ValueError as inst:
print ("The argument does not contain numbers\n", inst.args)
February 7, 2024 © Osmar R. Zaïane : University of Alberta 24
Raising Exception To Caller -2
def main():
('foo cannot handle this',)
try: Exception handled in main
foo() A string object is immutable
print('After function call')
except TypeError as e: # Caught as object e
print(e.args) # prints a tuple – try printing e.args[0]
print('Exception handled in main')
print('A string object is immutable')

def foo():
try:
astring = 'hello'
astring[0] = 'j'
except TypeError:
raise TypeError('foo cannot handle this') # propagating to caller

main()
February 7, 2024 © Osmar R. Zaïane : University of Alberta 25
Exception Class
Most built-in exceptions are derived from the
Exception class. For example: ArithmeticError,
IndexError, NameError, ValueError, TypeError,
AssertionError etc. are all derived from the
Exception class.
All user defined exceptions should also be derived
from the Exception class.
In a try statement with an except clause that
mentions the Exception class, that clause
handles any exception classes that are derived
from the Exception class.

February 7, 2024 © Osmar R. Zaïane : University of Alberta 26


Exception class in except
clause – order matters
def main(): Exception Class
try:
print(a)
except Exception:
print('Exception Class') def main():
Variable is not defined
except NameError: try:
print('Variable is not defined') print(a)
except: except NameError:
print('Some error') print('Variable is not defined')
except Exception:
main() print('Exception Class')
except:
print('Some error')

main()

February 7, 2024 © Osmar R. Zaïane : University of Alberta 27


Raising Exceptions
What can be raised as an exception?
Any standard Python exception
A new instance of Exception
Instances of our own specialized exception
classes
>>> try:
... print("Raising an exception")
... raise Exception('CMPUT', '175')
... except Exception as inst: # the exception instance
... print(inst.args) # arguments stored in .args
... x, y = inst.args # unpack args Raising an exception
... print('x =', x,'y =', y) ('CMPUT', '175')
X=CMPUT Y=175
February 7, 2024 © Osmar R. Zaïane : University of Alberta 28
Python Standard Exceptions
EXCEPTION NAME DESCRIPTION EXCEPTION NAME DESCRIPTION
Exception Base class for all exceptions EnvironmentError Base class for all exceptions that occur outside the
StopIteration Raised when the next() method of an iterator does Python environment.
not point to any object. IOError Raised when an input/ output operation fails, such
SystemExit Raised by the sys.exit() function. as the print statement or the open() function when
StandardError Base class for all built-in exceptions except trying to open a file that does not exist.
StopIteration and SystemExit. OSError Raised for operating system related errors.
ArithmeticError Base class for all errors that occur for numeric SyntaxError Raised when there is an error in Python syntax.
calculation. IndentationError Raised when indentation is not specified properly.
OverflowError Raised when a calculation exceeds maximum limit for SystemError Raised when the interpreter finds an internal
a numeric type. problem, but when this error is encountered the
FloatingPointError Raised when a floating point calculation fails. Python interpreter does not exit.
ZeroDivisonError Raised when division or modulo by zero takes place SystemExit Raised when Python interpreter is quit by using the
for all numeric types. sys.exit() function. If not handled in the code,
AssertionError Raised in case of failure of the Assert statement. causes the interpreter to exit.
AttributeError Raised in case of failure of attribute reference or TypeError Raised when an operation or function is attempted
assignment. that is invalid for the specified data type.
EOFError Raised when there is no input from either the ValueError Raised when the built-in function for a data type
raw_input() or input() function and the end of file is has the valid type of arguments, but the arguments
reached. have invalid values specified.
ImportError Raised when an import statement fails. RuntimeError Raised when a generated error does not fall into
KeyboardInterrupt Raised when the user interrupts program execution, any category.
usually by pressing Ctrl+c. NotImplementedError Raised when an abstract method that needs to be
implemented in an inherited class is not actually
LookupError Base class for all lookup errors.
implemented.
IndexError Raised when an index is not found in a sequence.
KeyError Raised when the specified key is not found in the
dictionary.
NameError Raised when an identifier is not found in the local or
global namespace.
UnboundLocalError Raised when trying to access a local variable in a
function or method but no value has been assigned
to it.

February 7, 2024 © Osmar R. Zaïane : University of Alberta 29


else clause
The try…except statement has an
optional else clause, which, when present,
must follow all except clauses.
The code in the else clause must be executed
if the try clause does not raise an exception
try:
f = open('myfile.txt')
except IOError :
print ("I/O error: File does not exist or cannot be read.")
else :
print("the file has", len(f.readlines()), "lines")
f.close()
February 7, 2024 © Osmar R. Zaïane : University of Alberta 30
finally clause
If you want to execute some code whether
an exception was raised or not, you can
use the optional finally clause
Guaranteed to be executed, no matter why
we leave the try block (i.e. executed under
all circumstances)
It is optional – you don’t have to have one.

February 7, 2024 © Osmar R. Zaïane : University of Alberta 31


Why use finally?
The finally clause is useful if you want
to perform some kind of “clean up”
operations before exiting the method –
example: closing a file

Also avoids duplicating code in each


except clause

February 7, 2024 © Osmar R. Zaïane : University of Alberta 32


finally example
>>> def divide(x, y):
... try:
... result = x / y Type error is re-raised after the
... except ZeroDivisionError: finally clause since no except
... print("division by zero!") exists for it.
... else:
... print("result is", result)
... finally: >>> divide(2, 1)
result is 2.0
... print("thank for dividing") thank you for dividing
>>> divide(2, 0)
division by zero!
finally clause is executed in any thank you for dividing
>>> divide("CMPUT", "175")
event.
thank you for dividing
• no exception Traceback (most recent call last):
• division by 0 File "<stdin>", line 1, in ?
• type error (not handled here) File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

February 7, 2024 © Osmar R. Zaïane : University of Alberta 33


Full Semantics of try-except-finally
If an expression in the try block raises an
exception:
The rest of the code in the try block is skipped.
If the exception “matches” the first except clause
the code in its except block is run
the code in the finally clause is run.
the rest of the except clauses are ignored.
the rest of the code in the method is run.
If the exception does not “match” the first except
clause, similar actions are taken for the first
“matching” except clause.

February 7, 2024 © Osmar R. Zaïane : University of Alberta 34


Full Semantics of try-except-finally
If the exception does not “match” any except
clause
the code in the finally clause is run
all other code in the method is abandoned
the exception is raised to the calling method – start
looking for some other portion of code that will
catch and handle the exception
If no exception is raised at all
all code in the try block is executed
The code in the else clause is run
the code in the finally clause is run
normal code in the method following finally is run
February 7, 2024 © Osmar R. Zaïane : University of Alberta 35
Possible Execution Paths
1. No exception occurs
1. Execute the try block
2. Execute the else and finally clauses
3. Execute the rest of the method
2. Exception occurs and is caught
1. Execute the try block until the first exception occurs
2. Execute the first except clause that matches the exception
3. Execute the finally clause
4. Execute the rest of the method
3. Exception occurs and is not caught
1. Execute the try block until the first exception occurs
2. Execute the finally clause
3. Propagate the exception to the calling method
February 7, 2024 © Osmar R. Zaïane : University of Alberta 36
Example of try-except-else-finally
def foo(a): What is the output for foo('10')?
try:
number = int(a) Lucky Number
2
print('Lucky Number')
100
size = len(a) All done
print(size) Goodbye
except ValueError:
print('Number Error') What is the output for foo(10)?
else: Lucky Number
print(number * number) All done
Traceback (most recent call last):
finally: File "exception-example2.py", line 14, in <module>
print('All done') foo(10)
File "exception-example2.py", line 5, in <module>
size = len(a)
print('Goodbye') builtins.TypeError: object of type 'int' has no len()
February 7, 2024 © Osmar R. Zaïane : University of Alberta 37
User-defined Exception
Python also allows you to create your own
Exception subclasses by deriving classes from
the standard built-in exceptions.

This allows you to conditionally match only


the Exceptions that you want to match.

This is useful when you need to display more


specific information when an exception is
caught.
February 7, 2024 © Osmar R. Zaïane : University of Alberta 38
Example related to RuntimeError
A class is created that is subclassed from
RuntimeError to display more specific
information. class Networkerror(RuntimeError):
def __init__(self, arg):
self.args = arg

Once the class is defined, the exception can


be raised
try:
raise Networkerror("Bad hostname")
except Networkerror as e:
print (e.args)
February 7, 2024 © Osmar R. Zaïane : University of Alberta 39
Create Own Exceptions
You may name your own exceptions by creating a new
exception derived from the Exception class
class MyError(Exception):
def __init__(self, value): The default __init__() of
self.value = value Exception has been
def __str__(self): overridden. The new
return repr(self.value) behavior simply creates the
value attribute replacing the
>>>try:
default behavior of creating
… raise MyError(2*2)
the args attribute.
… except MyError as e:
… print('My exception occurred, value:', e.value)

My exception occurred, value: 4
February 7, 2024 © Osmar R. Zaïane : University of Alberta 40
Assertions
An assertion is a statement that raises an
AssertionError Exception if a condition is not met.
assert Expression[, Arguments]
If the assertion fails, Python uses the given
argument as the argument for the AssertionError.
AssertionError exceptions can be caught and
handled like any other exception.

It is good practice to place assertions at the start


of a function to check for valid input, and after a
function call to check for valid output.
February 7, 2024 © Osmar R. Zaïane : University of Alberta 41
Assertion Examples
def KelvinToFahrenheit(Temperature):
assert (Temperature >= 0),"Colder than absolute zero!"
return ((Temperature-273)*1.8)+32

print (KelvinToFahrenheit(273)) try:


KelvinToFahrenheit("-23")
print (int(KelvinToFahrenheit(505.78)))
except AssertionError:
print (KelvinToFahrenheit(-5)) print ("Incorrect temp")
32.0 except TypeError:
451 print ("Not a number")
Traceback (most recent call last):
File "test.py", line 7, in <module> Not a number
print KelvinToFahrenheit(-5)
File "test.py", line 2, in KelvinToFahrenheit
assert (Temperature >= 0),"Colder than absolute zero!"
AssertionError: Colder than absolute zero!
February 7, 2024 © Osmar R. Zaïane : University of Alberta 42
Asserting valid input

from types import *

class MyDB:
...
def addRecord(self, id, name):
assert type(id) is IntType, "id is not an integer: %r" % id
assert type(name) is StringType, "name is not a string: %r" % name
...

February 7, 2024 © Osmar R. Zaïane : University of Alberta 43

You might also like