Monday, July 3, 2017

Summer of code 2017: Python, Day 16 Exceptions


As explained in my Summer of code 2017: Python post I decided to pick up Python

This is officially day 16. I took a couple of days off but today I looked at exceptions in Python, here are my notes


A couple of things to keep in mind when getting into exceptions



  • You can raise an exception to interrupt the flow of your program
  • You can handle an exception to resume control instead of the program being terminated
  • If you do not handle exceptions, unhandled exceptions will terminate the program.
  • Information about exception events will be contained in exception objects



Here is a simple function that converts an input to an integer, there is no exception handling done

>>> def converter(s):


    x = int(s)
    return x


>>> converter("33")
33
>>> converter("A")
Traceback (most recent call last):
  File "", line 1, in 
    converter("A")
  File "", line 4, in converter
    x = int(s)
ValueError: invalid literal for int() with base 10: 'A'
>>> 


As you can see it blows up with a ValueError exception

To catch an exception, you wrap a try except block around your statements, here is an example


>>> def converter(s):
 try:
  x = int(s)
 except ValueError:
  x = -1
 return x

>>> converter("33")
33
>>> converter("A")
-1
>>> 


As you can see no exceptions are displayed

You can also check for more than one exceptions like shown in the code below

>>> def converter(s):
    '''Convert to an integer.'''
    x = -1
    try:
        x = int(s)
        print("Conversion successful! x =", x)
    except ValueError:
        print("Conversion doomed!")
    except TypeError:
        print("Conversion doomed!")
    return x

>>> converter(33)
Conversion succesful! x = 33
33
>>> converter("a")
Conversion doomed!
-1
>>> converter(1.5555555)
Conversion succesful! x = 1
1
>>> converter([1,2])
Conversion doomed!
-1
>>>


We can simplify the code above by combining two exceptions into one check, you can see that in the code below

>>> 
def converter(s):
    '''Convert to an integer.'''
    x = -1
    try:
        x = int(s)
        print("Conversion successful! x =", x)
    except (ValueError, TypeError):
        print("Conversion doomed!")
    return x

>>> converter(33)
Conversion succesful! x = 33
33
>>> converter("a")
Conversion doomed!
-1
>>> converter([1,2])
Conversion doomed!
-1
>>> 


You need to have a statement after except, if you were to do the following, you will get a syntax error

>>> def converter(s):
    '''Convert to an integer.'''
    x = -1
    try:
        x = int(s)
        print("Conversion succesful! x =", x)
    except (ValueError, TypeError):
    return x
SyntaxError: expected an indented block


In Python to deal with a need for placeholder statement a pass statement can be used. Pass is a null operation, when it is executed, nothing happens. It is useful as a placeholder when a statement is required syntactically, but no code needs to be executed, for example:


>>> def converter(s):
    '''Convert to an integer.'''
    x = -1
    try:
        x = int(s)
        print("Conversion succesful! x =", x)
    except (ValueError, TypeError):
        pass
    return x

>>> 


These 3 errors should be handled during development and not at runtime

  • IndentationError
  • SyntaxError
  • NameError



If we want to print the exception that has been caught, you can assign it to a variable

Here is an example, e will hold the exception and then a print with a conversion to a string and format is used to print the exception to the console

>>> def converter(s):
    '''Convert to an integer.'''
    x = -1
    try:
        x = int(s)
        print("Conversion succesful! x =", x)
    except (ValueError, TypeError) as e:
        print("Conversion error: {}"\
        .format(str(e)),
        file=sys.stderr)
    return x

>>> import sys
>>> converter(10)
Conversion succesful! x = 10
10
>>> converter('a')
Conversion error: invalid literal for int() with base 10: 'a'
-1
>>> converter([1,2])
Conversion error: int() argument must be a string, a bytes-like object or a number, not 'list'
-1
>>> 


If you want to print the statement to the console but also raise the exception, you can use raise. Raise re-raises the last exception that was active in the current scope. Here is an example

def converter(s):
    '''Convert to an integer.'''
    x = -1
    try:
        x = int(s)
        print("Conversion succesful! x =", x)
    except (ValueError, TypeError) as e:
        print("Conversion error: {}"\
        .format(str(e)),
        file=sys.stderr)
        raise
    return x

>>> import sys
>>> converter(1)
Conversion succesful! x = 1
1
>>> converter('a')
Conversion error: invalid literal for int() with base 10: 'a'
Traceback (most recent call last):
  File "", line 1, in 
    converter('a')
  File "", line 5, in converter
    x = int(s)
ValueError: invalid literal for int() with base 10: 'a'
>>> 




If you have code that you want to run no matter what happens for example to 'cleanup' anything, you can use the finally keyword. Keep in mind that if you have multiple return statements, the one on the finally block is the one that will be returned.

Here is an example

>>> def foo():
 try:
  return 'trying...'
 finally:
  return 'finally'

 
>>> foo()
'finally'

That is all for today, I will continue with iterables next



No comments: