 # Exceptions

### 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)
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
• 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>

```

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

```try :
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 :
except Exception as e :
print ( "Exception", e.__class__, "occured")

```
```Exception <class 'KeyError'> occured
```

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

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")
print ( "divisor = ", line )

# now divide the age by the divisor
new_age = age/int(line)
print ( "new age = ", new_age)

except FileNotFoundError :
```divisor =  0