Python Exceptions

Exceptions


  Machine Learning in Python

Contents

What are Exceptions

age     = 22
divisor = 2
# How old would I be if I am half my age ?

new_age = age / divisor

print ( "If I were half my age, I would be", new_age, "years old")

If I were half my age, I would be 11.0 years old

Say, you don’t want to just half it – you want to divide it by a third or by a fourth. Let the user decide it.

divisor = int(input("enter divisor - "))
new_age = age / divisor

print ( "If I were half my age, I would be", new_age, "years old")

If I were half my age, I would be 7.333333333333333 years old

So far so good. What if the user enters a wrong value ? Let’s try the same again

divisor = int(input("enter divisor - "))

new_age = age / divisor

print ( "If I were half my age, I would be", new_age, "years old")

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-4-94e3a3ad913d> in <module>
      1 divisor = int(input("enter divisor - "))
      2 
----> 3 new_age = age / divisor
      4 
      5 print ( "If I were half my age, I would be", new_age, "years old")

ZeroDivisionError: division by zero

Since we are trying to divide the age by zero(0), Python has thrown an error – ZeroDivisionError. The problem with these kind of errors is that Python stops the execution of the file. We don’t want that to happen right ? You have never seen websites stop or programs (like excel, word or even a mobile app ) quit running suddenly. Well, if they do, it is a big deal – it is a bug.


Try Catch block

How to deal with it ? Since we don’t know the error that might be thrown, we let python try it first, and provide a way to handle this exception.

try : 
    divisor = int(input("enter divisor - "))

    new_age = age / divisor
    print ( "If I were half my age, I would be", new_age, "years old")

except : 
    print ( "exception occured")
exception occured

This is a much better way to handle the exception isn’t it ? Instead of throwing a huge error message, we are programming it to handle the exception in a graceful way.


Exception Examples

But how do you know what kind of error has occured ? Divide by zero is just one kind of error. There are many other errors that could occur – like

  • SyntaxError – Syntax error.
  • ZeroDivisionError – Divide by zero
  • KeyError – Key is not found in the dictionary
  • TypeError – Invalid operation for the specific type

We will see some examples of these.

SyntaxError – What happens if you write the wrong syntax ? For example, if you try the print statement without the parantheses.

print "hi"

File "<ipython-input-24-2b2d809635ce>", line 1
    print "hi"
             ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print("hi")?

Typically, in application development, these type of exceptions are never caught explicitly. We have already seen the ZeroDivisionError at the beginning of this section. Let’s see the KeyError.

KeyError – This kind of error happens when you try to access a dictionary element with a wrong key. Let’s take an example.

population = {"india"    :1367097934,
              "china"    :1419518156,
              "US"       :328830848 }

Let’s try and see what happens if we ask for the population of canada ( which is not available in the dictionary).

population["canada"]

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-16-1f8be354c054> in <module>
----> 1 population["canada"]

KeyError: 'canada'

KeyError exception is thrown. Let’s check if we can catch this using a try block.

try :
    print ( population["canada"])
except Exception as e :
    print ( "Exception", e, "occured")

Exception 'canada' occured

That’s not the name of the exception. To get the actual exception class, use the class attribute of the Exception base class.

try :
    print ( population["canada"])
except Exception as e :
    print ( "Exception", e.__class__, "occured")

Exception <class 'KeyError'> occured

try:
    names = ["United States", "China", "India"]
    names[3]

except Exception as e : 
    print (e)
Question – Try the code above in your system and identify what is the exception that occurs.
IndexError
ListError
RangeError
# Program to find out if a number is prime or not

number = int(input("enter number - "))
i = int(number/2) + 1

while i >= 2 :
    if number % i == 0 :
        print ( "not a prime number")
        break
    i = i - 1
else :
    print ( "prime number")
Question – Try the code above in your system and identify what possible exceptions can be thrown ?
ValueError
LoopError
RangeError
i = "1" + 1
Question – Try the code above in your system and identify which error is thrown ?
TypeError
IntegerError
RangeError

Catch specific exceptions

TypeError – We will see another exception before we look at the exception hierarchy. Let’s try and add a string to an integer and see what happens.

age = 21
age = age + "1"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-20-1ca2a7cce752> in <module>
      1 age = 21
----> 2 age = age + "1"

TypeError: unsupported operand type(s) for +: 'int' and 'str'

Python throws a TypeError exception. As usual, you can either catch that specific exception or use the generic Exception class.

age = 21
try :
    age = age + "1"
    age = age / 0
except TypeError:
    print ( "cannot add integer to string")
except ZeroDivisionError :
    print ( " divide by zero error ")
except KeyError :
    print ( " dictionary key error ")

cannot add integer to string

You can get the entire list of standard Python exceptions here. Now, let’s now see the exception hierarchy.


Exception Hierarchy

Exceptions in Python follow a hierarchy. Here is a brief snapshot of the class hierarchy of Python Exceptions. We have highlighted a couple of the exceptions that we have seen before.

You can get a list of the entire Python exception heirarchy here.


finally

When you try to access resources ( databases, files etc), typically you open and close access ( connection) to these resources. When you are done with the resource ( read the data or perform transactions ), you are supposed to close the resource. Here is a crude example – when you open your locker door and access what you need, immediately you close the locker door – isn’t it ?

What happens when an exception occurs during the process of accessing the resource. For example, when you open a file and perform some operations, say if something fails and Python throws an exception.

  • If you don’t catch the exception, the program just stops execution. This leaves the door open ( resource handle open )
  • If you catch the exception, there could be many of them. Eventually you would have to close the door, but in which exception would you close the door ?

This is where the finally block comes in. Irrespective of which exception is thrown by the program, the finally block is always executed.

age = 21
try : 
    file = open ( "./data/divisor.txt")
    line= file.read()
    print ( "divisor = ", line )
    
    # now divide the age by the divisor
    new_age = age/int(line)
    print ( "new age = ", new_age)

except FileNotFoundError :
    print ( " file not found ")

except ZeroDivisionError :
    print ( "Divide by zero error" )

finally :
    print ( "closing file")
    file.close()
divisor =  0
Divide by zero error
closing file
%d bloggers like this: