Python – Exceptions and Error Handlings

If you write a complex python code , it is very important to handle errors and exceptions. While handling files, connecting to database systems and so on , you can be the best programmer in the world and still get errors that is not up to you. When you write a code for infrastructure, you need to raise exceptions and warnings to let other developers to use you code correctly.

In this post, i will go over errors, exceptions, warnings and related topics

Warnings

You can add warnings to your code.

Simple example

import warnings

def fn(a):
    s=0;
    if a>100:
        warnings.warn('Long Wait...')
    for i in range(a):
        s+=i
    return s

print("Start...")
print(fn(1000))
print ("Ending...")

If you run it you will see the following warning message:

# python ./demo.py 
Start...
./demo.py:14: UserWarning: Long Wait...
  warnings.warn('Long Wait...')
499500
Ending...

You can run it without the warning using one of the following methods

command line:

# python -W ignore ./demo.py 
Start...
499500
Ending...

using PYTHONWARNINGS environment variable

# export PYTHONWARNINGS=ignore
# python ./demo.py 
Start...
499500
Ending...

in the code:

warnings.filterwarnings('ignore','.*')

print(fn(1000))

if you use one of the above methods with ‘error’ instead of ‘ignore’, you will get an error message and the program execution stops

# export PYTHONWARNINGS=error
# python ./demo.py 
Start...
Traceback (most recent call last):
  File "./demo.py", line 25, in <module>
    print(fn(1000))
  File "./demo.py", line 14, in fn
    warnings.warn('Long Wait...')
UserWarning: Long Wait...

 

Error Messages

Python routes its own error messages to stderr but it cannot know which of your messages are errors. You can write to stderr using print command (python 2.7) or function (python 3.6).

# python 2.7
print >> sys.stderr,"Wrong Argument..."

# python 3.6
print("Wrong Argument", file=sys.stderr)

The syntax is different so if you want to write version independent code use sys module:

import sys

if arg1>0:
    sys.stderr.write("Wrong Argument...\n")
    exit(1)

 

Exception Handling

Sometimes you don’t know if your task completed successfully until you try. For example while accessing a web server it may be offline, so you need to send request and wait for response and after a timeout generate error. Thats why we need exceptions. Exception handling is not error handling, you will not use exception for something you can check for example if you divide x/y , check that y is not zero using if statement and not using exceptions

In Python an exception can be thrown , it is represented by an object (a class derived from the Exception). Throwing an exception transfers control and the function call stack is unwound until a handler capable of handling the Exception object is found

Simple example:

print("start")
try: 
    print("start try block")
    f = open("file1") 
    print("end try block")
except Exception:
    print("error opening file")

print("end")

If the file doesn’t exists you will see the following output:

start
start try block
error opening file
end

Any exception in the try block transfers control to the except block. If the file exists the except block is ignored:

start
start try block
end try block
end

You can write multiple except block and also multiple exceptions for each block for example:

print("start")
try:
    print("start try block")
    f = open("file1")
    print("end try block")
except IOError:
    print("error opening file")
except (OSError,NameError):
    print("OS/Name problem")
except Exception:
    print("All other Exceptions")
print("end")

Note that the first except block that match the exception type will be executed so the order is important. If you place the last except block (except Exception) before any other exception it will catch it

Exception Object

You can use the exception object to get more details about the exception:

print("start")
try:
    print("start try block")
    f = open("file1")
    print("end try block")
except IOError as errobj:
    print("error opening file:",errobj)
print("end")

Output:

start
start try block
error opening file: [Errno 2] No such file or directory: 'file1'
end

 

Else Block

You can add else block to the try – except blocks. It will run if no exception occurred.

print("start")
try:
    print("start try block")
    f = open("file1")
    print("end try block")
except IOError as errobj:
    print("error opening file:",errobj)
else:
    print("No Exceptions") 

print("end")

It is similar to add more statements at the end of the try block, the only difference is what happens  if the statement in the else block generate an exception, it will transfer control to the calling function.

For Example:

def f2():
    try:
        print("f2")
        f = open("file1")
    except Exception as e:
        print("Exception in f2")
    else:
        print("No Exceptions")


def f1():
    try:
        print("start try block")
        f2()
        print("end try block")
    except Exception:
        print("Exception in f1")



print("start")
f1();
print("end")

If the file doesn’t exists the output is:

start
start try block
f2
Exception in f2
end try block
end

But if we move the open function to the else block:

def f2():
    try:
        print("f2")
    except Exception as e:
        print("Exception in f2")
    else:
        print("No Exceptions")
        f = open("file1")


def f1():
    try:
        print("start try block")
        f2()
        print("end try block")
    except Exception:
        print("Exception in f1")



print("start")
f1();
print("end")

The exception is now handled on f1:

start
start try block
f2
No Exceptions
Exception in f1
end

The Finally Block

You can add a finally block which is (almost) always executed, even if an exception occurs

print("start")
try:
    print("start try block")
    f = open("file1")
    print("end try block")
except IOError as errobj:
    print("error opening file:",errobj)
else:
    print("No Exceptions")
finally:
    print("Always Executed")
print("end")

Output without exception:

start
start try block
end try block
No Exceptions
Always Executed
end

Output with exception

start
start try block
error opening file: [Errno 2] No such file or directory: 'file1'
Always Executed
end

The main use of the finally block is to release resources (locks, files, etc.)

You can write code with try and finally only if you handle the exception in the calling function

Raising Exceptions

You can raise exceptions in your code. It is useful if you don’t want to return normally

For example:

def f2(a,b):
    if a>0:
        raise ValueError("Error in f2")
    return a+b

def f1():
    print("start f1")
    s=f2(10,20)
    print("end f1",s)

print("start")
f1();
print("end")

On exception, the program terminated

# python3 ./demo7.py 
start
start f1
Traceback (most recent call last):
  File "./demo7.py", line 18, in <module>
    f1();
  File "./demo7.py", line 10, in f1
    s=f2(10,20)
  File "./demo7.py", line 4, in f2
    raise ValueError("Error in f2")
ValueError: Error in f2

Writing Your Own Exception Class

To create a new type of exception derive a class from Exception class:

class CustomException(Exception):
    pass

def fn(*arguments):
    if not all(arguments):
        raise CustomException("False argument in fn")


try:
    fn('dev','',42)
except CustomException as err:
    print("Oops:",err)

You can add some magic methods to provide useful operations (__str__ for example)

Subscribe to our list

Loading

 

 

 

 

 

Tagged