Exception handling allows us to enforce constraints on variables to implement our business logic in the computer program and it also enables us to write a robust program which can handle different types of errors occurred during execution. In python, we use try-except blocks to implement exception handling. In this article, we will look at some ways to write an efficient python program by looking at illustrations to best use try-except in python.So, let’s dive into it.

### Raising Exceptions Manually using raise keyword

A python program throws inbuilt exceptions automatically when an error occurs but we can also raise inbuilt exceptions manually using raise keyword. By throwing inbuilt exceptions using raise keyword, we can use the inbuilt exceptions to enforce constraints on the variables to make sure that program is correct logically. Here the point to keep in mind is that  a program  may not throw any error but it may give an unrealistic value as output when proper constraints are not applied on the variables. Hence we may use raise keyword to throw exceptions in the python try-except block to enforce the constraints.

For example, suppose we want to calculate the year of birth of a person from their age, we can do it as following:

age= 10
print("Age is:")
print(age)
yearOfBirth= 2021-age
print("Year of Birth is:")
print(yearOfBirth)

Output:

Age is:
10
Year of Birth is:
2011

We can see that the program has given correct output for a person of age 10. Now we will try to give a negative age as input to the program and see what happens.

age= -10
print("Age is:")
print(age)
yearOfBirth= 2021-age
print("Year of Birth is:")
print(yearOfBirth)

Output:

Age is:
-10
Year of Birth is:
2031

In the above output, we can see that the program has executed successfully and has given an output which is logically impossible because no person can have his year of birth in future. So, we will use try-except error handling code to raise an error manually when age is negative and then we will show the proper output as follows.

try:
age= -10
print("Age is:")
print(age)
if age<0:
raise ValueError
yearOfBirth= 2021-age
print("Year of Birth is:")
print(yearOfBirth)
except ValueError:
print("Input Correct age.")

Output:

Age is:
-10
Input Correct age.

Here, we can see that when the input age is a negative value, the program raises ValueError manually and the error is handled by the code in except block. We can also define custom exceptions on our own to implement the constraints as discussed in the following section.

### Using custom exceptions

To enforce the constraints we can declare our own exceptions by defining classes which should be sub classes of any inbuilt exception. In this way we can create an exception with a name more meaningful to our constraints and then we can enforce the constraints on the variables by checking and raising custom exceptions.

In the following example, we define NegativeAgeError exception class by inheriting the python Exception class . Whenever the value of age in input is negative, the custom error named as NegativeAgeError is raised and then it is handled by the code in the except block. Whenever positive value of age is given as input, the program will work normally.

class NegativeAgeError(Exception):
pass
try:
age= -10
print("Age is:")
print(age)
if age<0:
raise NegativeAgeError
yearOfBirth= 2021-age
print("Year of Birth is:")
print(yearOfBirth)
except NegativeAgeError:
print("Input Correct age.")

Output:

Age is:
-10
Input Correct age

### Differentiating between different types of errors using try-except in python

There may be many situations where we want to handle different runtime and custom exceptions differently. We may want to find out which exception is occurring during execution of a program or we may want to execute different tasks when different exceptions occur. In these cases we can catch each exception separately by giving the exception name as an argument to except block as given in the following example and then we can execute the statements given in the  except block for that specific exception.

try:
age= -10
print("Age is:")
print(age)
assert age>0
yearOfBirth= 2021-age
print("Year of Birth is:")
print(yearOfBirth)
except AssertionError:
print("Input Correct age.")
except ValueError:
print("ValueError occured")
except NameError:
print("NameError occurred")
except:
print("Some other exception occurred")

In the above program, we have explicitly differentiated AssertionErrorValueError and NameError from other types of exceptions and we have handled them explicitly. One has to be kept in mind while differentiating exceptions is that the most general exception has to be written last in the except block and most specific exception has to be written first in the except block. Otherwise unreachable code will be generated and will cause error.

For example, following way of using try-except in python to differentiate exceptions is wrong.

try:
age= -10
print("Age is:")
print(age)
raise IOError
yearOfBirth= 2021-age
print("Year of Birth is:")
print(yearOfBirth)
except:
print("Some other exception occurred")
except AssertionError:
print("Input Correct age.")
except ValueError:
print("ValueError Occured")
except NameError:
print("NameError occurred")

Output:

File "/usr/lib/python3/dist-packages/IPython/core/interactiveshell.py", line 3331, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)

File "<ipython-input-4-f6b48848354a>", line 1, in <module>

File "/usr/lib/python3/dist-packages/spyder_kernels/customize/spydercustomize.py", line 827, in runfile
execfile(filename, namespace)

File "/usr/lib/python3/dist-packages/spyder_kernels/customize/spydercustomize.py", line 110, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)

File "/home/aditya1117/untitled0.py", line 8
print(yearOfBirth)
^
SyntaxError: default 'except:' must be last

We can see that syntax error occurs in the program when we use more general except block before the specific exceptions.

### Grouping Exceptions using try-except in python

While writing programs, there may be many situations where we want to handle two or more exceptions in the same way. We can group certain types of exceptions at one place in python and then they can be handled by the same error handling code by passing each exception of a group as an argument to the except block.

In the example below, we have grouped AssertionErrorValueError and NameError in a single except block and same code will be executed when any of the error occurs.

try:
age= -10
print("Age is:")
print(age)
raise ValueError
yearOfBirth= 2021-age
print("Year of Birth is:")
print(yearOfBirth)
except (AssertionError,ValueError,NameError):
print("AssertionError or ValueError or NameError has occurred.")
except:
print("Some other exception occurred")

### The finally block

In a program, there may be some statements to execute each time before the program terminates no matter what the situation is. In that case we can put the statements in Finally block. The Finally block executes each time whether or not any error/exception occurs in the try block. When an exception is thrown by the try block, the code in the except block executes first and then the code in the finally block is executed. Otherwise Finally block is executed after the try block when any error doesn’t occur.

For example, when we perform python write to file operation, the file always needs to be closed before termination of the program so that the data doesn’t get lost. We can write code to close the file in the Finally block in this case as follows.

try:
file_ptr=open("filename.txt","w")
file_ptr.write("This is PythonForBeginners.com")

except (IOError):
print("IOError has occurred.")
except:
print("Some other exception occurred")
finally:
file_ptr.close()

### Conclusion

In this article, we have seen how we can best use try-except in python by application of methods like custom exceptions, grouping the exceptions and differentiating the exceptions from each other. Stay tuned for more informative articles.