Exception Handling and Generators in Python

While writing programs it is natural to commit error, may it be a spelling mistake, an indentation error or something else. When writing programs, it becomes difficult to quickly get through these errors especially when your code is long enough. At such times, to catch these errors and make your program work properly, every language has a specific mechanism. Similarly, Python also has its ways of preventing and catching error and this mechanism is called exception handling.

So let’s first understand what type of exceptions can be handled by python

What is an Exception?

Any unexpected error that occurs during the execution of the program can be termed as an exception.

Errors

So broadly there are two types of errors:

  1. Compile-time errors

These errors occur when there is some mistake in the grammar rules of the programming language.

For example any syntax error, if you try to add a string and an integer it will cause an error.

  1. Run-time errors

These errors occur during the runtime because of unexpected situations. 

For example, division by zero is a runtime error.

Common cases of Exceptions

  1. Division by zero error
  2. Invalid input
  3. Accessing the elements of an array beyond its range
  4. Opening a file which does not exist
  5. Hard disk crash
  6. Heap memory exhausted

What is exception handling?

Exception handling is a way of handling exceptions that occur during the runtime of the program and causes the program flow to terminate.

Built-in Python Exceptions

Exception NameDescription
ZeroDivisionErrorRaised when there is division by zero
EOFErrorRaised when the built-in functions input() or raw_input() reaches the end of file (EOF) condition without reading any data.
IOErrorRaised when any input or output operation like opening a file or using print statement fails
IndexErrorRaised when index is out of range
NameErrorRaised when a local or global name is not found.
ImportErrorRaised when import statement fails to find the module to be imported
TypeErrorRaised when the type is inappropriate. For example when we try to calculate the root of a string value, a type error is raised.
ValueErrorRaised when the type is correct but the value is inappropriate.
OverflowErrorRaised when the result of an arithmetic operation is too large to be represented
KeyErrorRaised when the mapping/ dictionary key is not found in the set of existing keys

Exception Handling in Python

In python, exception handling is done using the try and except clauses.

The code that may generate an error is written in the try block and if the exception is raised then what steps should be done is written in the exception block.

The syntax for the same is

try:

   “Code that can cause an exception”

except:

    “What to do when the Exception occurs ”

For example

Lets handle the Division by zero error

 try:

     print “division1 = ”,(4/2)

     print “division2 = ”, (4/0)

 except:

     Print “Division by Zero not possible! Change the denominator value.” 

The output of the above code will be – 

division1 = 2

division2 = Division by Zero not possible! Change the denominator value.

Let’s take another example where we take an input from the user and try to convert it into integer.

 try:

    a = input(“Enter your value”)

    y = int(a)

 except:

    print “Invalid input! Enter a numerical value!” 

Here if the user enters for example, a string value then it will raise an exception as string cannot be converted into an integer.

Also Read How to convert a list to a string in Python?

 Handling Multiple Exceptions

A single program can have different types of errors, so to debug the same it is better to raise a different exception according to the type of error occurred. This can be done by giving multiple exceptions.

Let’s take the case of opening a file and performing some operations on its data.

 try: 

    ufile = open(“abc.txt”)

    uread = ufile.readline()

    uint =  int(s.strip())

    val = 201/uint

 except IOError:

    print “I/O Error!”

 except ValueError:

    print “unable to convert to integer! Check your input”

 except ZeroDivisionError:

     print “Division by zero not possible!”

 except :

    print “unexpected error”

 else:

    print “ No error!” 

The output for the above code is

I/O Error!

Execution Order

First, the try block is executed and if inside it an exception is raised, it will look for a named exception and if not it will execute the unnamed except block.

Now what is named and unnamed except blocks?

The named except: blocks handle the named exceptions for example as we didi above in the case of Multiple exceptions, the ZeroDivisionError, the I/O Error and so on.

While the unnamed except block is the one which handles all the other exceptions i.e. the exceptions not mentioned in the named except blocks, as we did in the above case where at last we gave except: block to handle error other than the mentioned ones, if any.

The finally Block

Finally block is used when you want some part of code which has to execute any how

But in case of try block it may or may not be executed depending on if any error occurred.

The syntax for a finally block will be

try: 

   “Code that may raise an exception”

except: 

    “Handle exception here”

finally: 

    “Code that will always execute”

For example,

 try: 

    Mfile =open(“abc.txt”, “r”)

    print Mfile.read()

 except:

    print “exception occurred!”

 finally:

    print “Finally done!” 

Now looking at the output

If there is an exception, the output would be- 

exception occurred!

Finally done!

Now if there is no exception, the output will be-

Finally done!

Raising an Exception

Using the raise keyword, you can force an exception to occur.

You can also pass a custom message to the exception handling module.

Syntax –

 raise <exception> [, message]

For example, 

Raising a ZeroDivisionError

 try: 

     a = int(raw_input(“numerator”))

     b = int(raw_input(“denominator”))

     if b == 0:

          raise ZeroDivisionError, str(a) + “/0 is not possible”

    print a/b

 except ZeroDivisionError, e :

    print “Exception”, e.message 

Note: We are using Python2.7 here, if you are working on python3, there would be a slight change in syntax.

The output for the above code will be-

numerator 2

denominator 0

Exception 2/0 is not possible

Raising a User-defined Exception

The exceptions we talked about till now were all built-in functions. In python, you can also have user-defined exceptions and raise them according to your requirements.

Now, for raising a user-defined exception, you need to define an exception class using the syntax below

class <name of user defined exception> (Exception) : 

     pass

Then you can create objects to use this exception class

For example,

 Class myError (Exception):

    pass

 Error1  = myError(“Negative input not allowed”)

 try:

    val = float(raw_input(“Enter value”))

    if val < 0:

        raise Error1

    else: 

         print “OK”

 except myError, e:

      print “Error”, e.message 

Generators in Python

What is a generator function?

A generator function is a special function that automatically suspends and resumes its execution and state around the point of value generation. 

It returns the generated value through the yield statement.

What is a yield statement?

A yield statement suspends the function retaining its current state. 

Also, it sends a value to the caller.

The syntax for yield statement is

yield <value>

Now that we understand what are generators, we should also understand how a generator is similar and different from a function.

It is similar because

Generator function uses def statement

It can be invoked

It takes parameters like a function does

But it is also different from a function because

It yields value one at a time instead of generating an array of values.

So to sum up we can say that a generator is like a function in many ways but its behaviour is more like an iterator which returns one value at a time.

So that was all about exception handling and generators in Python. Good Day!

Related posts

Five Ways to Calculate Power in C++

File Permissions in Linux

Implementing Stacks and Queues