Exceptions

An exception is an event which occurs during the execution of a program and that disrupts the normal flow of the program's instructions. When a Python code generates an exception, it must either handle the exception immediately or raises it. Otherwise execution terminates.

Exception are objects, organized in a tree.

1. Handling (solving) exceptions

1.1 Catching exceptions

Exceptions are used for handle errors or inusual situations.


In [ ]:
# Note: You must interrupt the kernel (see the menu) in order to simulate <ctrl>+c.
try:
    text = input('Please, enter something (or stop the kernel): ')
except:
    print('Sorry, something wrong happened :-(')
    
# This command never should be executed if you didn't provide an input
print('You entered "{}".'.format(text))

1.2 Defining alternatives with else

The else statement solves the previous problem (run unwanted code).


In [ ]:
try:
    text = input('Please, enter something: ')
except:
    print('Sorry, something wrong happened :-(')
else:
    # Now this statement is executed only if you provided an input
    print('You entered "{}".'.format(text))

1.3 Finally, the finally code is executed yes or yes

No matter what happend in the rest of sections of the try statement (even if an exception is thrown in these sections).


In [ ]:
try:
    text = input('Please, enter something: ')
except:
    print('Sorry, something wrong happened :-(')
else:
    print('You entered "{}".'.format(text))
finally:
    # This will always executed, with exception or not.
    print('Thanks for your interaction!')

1.4 Discriminating exceptions

The except statement accepts the type of exception as an argument. This is suitable to refine the exception handling.


In [ ]:
try:
    text = input('Please, enter something: ')
except EOFError: # Exception specific for input()
    print('Sorry, you didn\'t enter anything (<ctrl>+d) :-(')
except KeyboardInterrupt: # Exception raised when a program is interrupted
    print('Sorry, you cancelled the input (<ctrl>+c) :-(')
else:
    print('You entered "{}".'.format(text))
finally:
    print('Thanks for your interaction!')

1.5 Handling several exceptions in the same way


In [1]:
try:
    x = 1/0
except (ArithmeticError, ZeroDivisionError):
    print('Some arithmetic issue has been arised :-/')


Some arithmetic issue has been arised :-/

2. Raising exceptions

Sometimes we don't want (or don't know :-) how to manage an exception in the current function (or method). In this case, the exception can be propagated upwards the code called (directly or indirectly) by the exception. Exceptions generated by a statement are documented and accesible through the built-in help() function.


In [ ]:
def keyboard_input():
    try:
        text = input('Please, enter something: ')
        return text
    except KeyboardInterrupt: # Exception raised when a program is interrupted
        print("Sorry, you can't cancel the input :-(")
        raise

while True:
    try:
        print('You entered:', keyboard_input())
        break
    except KeyboardInterrupt:
        print('Please, try again')

3. Creating (new type of) exceptions

Exceptions can be created, for example, to increase the functionality of an existing one. All exceptions must be derived (directly or indirectly) from the Exception class.


In [ ]:
class SmallStack_full(Exception):
    pass
    
class SmallStack_empty(Exception):
    pass

class SmallStack():
    '''A stack structure with 10 slots.'''
    
    def __init__(self):
        '''Create the stack.'''
        self.stack = [None]*10
        self.counter = 0
        
    def push(self, x)->None:
        '''Put "x" on the stack.
        
        Raises SmallStackFull upon fullness.
        '''
        if self.counter < 10:
            self.stack[self.counter] = x
            self.counter += 1
        else:
            raise SmallStack_full
        
    def pop(self)->object:
        '''Remove the last element inserter in the stack.
        
        Raises SmallStackEmpty upon emptyness.
        '''
        if self.counter > 0:
            self.counter -= 1
            return self.stack[self.counter]
        else:
            raise SmallStack_empty

s = SmallStack()

try:
    for i in range(100):
        s.push(i)
        print(i)
except SmallStack_full:
    print('The stack is full. i={}'.format(i))
    
try:
    for i in range(100):
        print(i, s.pop())
except SmallStack_empty:
    print('The stack is empty. i={}'.format(i))

4. Asserting

Assertions are statements that throw an exception (AssertionError) when some condition is true. For this reason they are used in testing time. Assertions are ignored when the interpreter is invoked in release mode (using the -O flag).


In [ ]:
! cat testing_assertions.py

In [ ]:
! python testing_assertions.py

In [ ]:
! python -O testing_assertions.py