CH 7-1
CH 7-1
1. Errors
Errors are problems that occur in the program due to an illegal operation performed by the user
or by the fault of a programmer, which halts the normal flow of the program. Errors are also
termed bugs or faults. There are mainly two types of errors in python programming. Let us learn
about both types of python errors:
1. Syntax errors
2. Logical Errors or Exceptions
Whenever we do not write the proper syntax of the python programming language (or any other
language) then the python interpreter throws an error known as a syntax error.
On the other hand, Logical Errors are those errors that cannot be caught during compilation time.
As we cannot check these errors during compile time, we name them Exceptions. Exceptions can
cause some serious issues so we should handle them effectively.
Note: Syntax errors can also be called Compile Time Error. Some of the most common compile-
time errors are syntax errors, library references, incorrect import of library functions and
methods, uneven bracket pair(s), etc.
Syntax Errors
A syntax error is one of the most basic types of error in programming. Whenever we do not write
the proper syntax of the python programming language (or any other language) then the python
interpreter or parser throws an error known as a syntax error. The syntax error simply means that
the python parser is unable to understand a line of code.
number = 100
if number > 50
print("Number is greater than 50!")
Output:
Some of the general syntax errors can be typing errors (errors), incorrect indentation, or incorrect
arguments. In case of syntax errors, we should look at our code and try to understand the
problem.
Note: In various IDEs (Integrated Development Environment), the syntax error(s) are shown by
red dashed lines.
Logical Errors
As we have seen above there are two main types of python errors. We already have studied the
syntax error, let us now learn about the logical errors in python.
Logical Errors are those errors that cannot be caught during compilation time. As we cannot
check these errors during compile time, we name them Exceptions. Since we cannot check the
logical errors during compilation time, it is difficult to find them.
There is one more name of logical error. Run time errors are those errors that cannot be caught
during compilation time. So, run-time can cause some serious issues so we should handle them
effectively.
Let us now talk about some of the most common logical types of errors in python programming.
ZeroDivisionError Exception
ZeroDivisionError is raised by the Python interpreter when we try to divide any number by zero.
Let us take an example to understand the ZeroDivisionError.
number = 100
divided_by_zero = number / 0
print(divided_by_zero)
Output:
The Indentation error is another type of error in python that can be summed up inside the syntax
error. As we know, we use indentation to define a block of code in python. So, in case of
improper indentation, the Python interpreter raises an Indentation error. Let us take an example
to understand the Indentation Error.
number = 57
if number == 57:
print(57)
Output:
Like any other programming language, Python has some built-in exceptions.
Note: All instances in Python must be instances of a class that derives from BaseException.
Exception Description
As the name suggests, the IndexError is raised when the wrong index of
IndexError
a list is used.
KeyError KeyError is raised when the key of the dictionary is not found.
EOFError is raised when the input() function hits the condition of end-
EOFError
of-file.
RuntimeError is raised when an error does not fall under any other
RuntimeError
category of built-in Python exceptions.
• Errors are the problems that occur in the program due to an illegal operation
performed by the user or by the fault of a programmer, which halts the normal flow of
the program.
• Errors are also termed bugs or faults. There are mainly two types of errors in python
programming namely - Syntax errors and Logical Errors or Exceptions.
• Whenever we do not write the proper syntax of the python programming language (or
any other language) then the python interpreter throws an error known as syntax
error.
• Syntax errors can also be called Compile Time Error. Some of the most common
compile-time errors are syntax errors, library references, incorrect import of library
functions and methods, uneven bracket pair(s), etc.
• Logical Errors are those errors that cannot be caught during compilation time. As we
cannot check these errors during compile time, we name them Exceptions.
• Exception Handling is the process of handling errors and exceptions such that the
normal execution of the system is not halted.
2. Runtime Errors
• A runtime error in a program is one that occurs after the program has
been successfully compiled.
• The Python interpreter will run a program if it is syntactically correct (free
of syntax errors). However, if the program encounters a runtime error - a
problem that was not detected when the program was parsed and is only
revealed when a specific line is executed - it may exit unexpectedly
during execution. When a program crashes due to a runtime error, we say
it has crashed
Some examples of Python Runtime errors
• division by zero
• performing an operation on incompatible types
• using an identifier that has not been defined
• accessing a list element, dictionary value, or object attribute which
doesn’t exist
• trying to access a file that doesn’t exist
Let's take a closer look at each of them by using an example
Division by zero
If we divide any number by zero, we get this error.
Algorithm (Steps)
Following are the Algorithm/steps to be followed to perform the desired task −
• Take a variable to store the first input number.
• Take another variable to store the second input number(Here the second
number should be 0).
• Divide the first number by the second number and print the result.
Example
The following program returns the runtime error if we divide a number with zero −
firstNumb = 11
secondNumb = 0
print(firstNumb/secondNumb)
Output
On executing, the above program will generate the following output −
Traceback (most recent call last):
File "main.py", line 6, in <module>
print(firstNumb/secondNumb)
ZeroDivisionError: division by zero
Because the second number is 0 and no number can be divided by 0, we get a runtime
error.
# Input string
inputString = "TutorialsPoint"
# Input Number
inputNumber = 11
print(inputString + inputNumber)
Output
On executing, the above program will generate the following output −
Traceback (most recent call last):
File "main.py", line 6, in <module>
print(inputString + inputNumber)
TypeError: must be str, not int
We can't add an integer to the string data type here, so we get a type error (runtime
error).
Example
The following program returns the runtime error if we are using undefined identifier −
Output
On executing, the above program will generate the following output −
Traceback (most recent call last):
File "main.py", line 2, in <module>
print(tutorialsPoint)
NameError: name 'tutorialsPoint' is not defined
Because we did not define the tutorialsPoint identifier and are accessing it by printing
it, a runtime error occurs (Name error).
Algorithm (Steps)
Following are the Algorithm/steps to be followed to perform the desired task −
• Create a list and assign some random values to it.
• Access the list element by index by giving the index that doesn’t exist and
printing it.
Example
The following program returns the index error if we access an element out of range −
# input list
inputList =[1, 4, 8, 6, 2]
Output
On executing, the above program will generate the following output −
Traceback (most recent call last):
File "main.py", line 6, in <module>
print("Element at index 10:", inputList[10])
IndexError: list index out of range
There are 5 elements in the list, and we are attempting to access the 10th index,
which does not exist, resulting in an index error.
Algorithm (Steps)
Following are the Algorithm/steps to be followed to perform the desired task −
• Create a variable to store the path of the text file. This is a fixed value. In
the example below, this value must be substituted with the file path from
your own system.
• Use the open() function(opens a file and returns a file object as a result)
to open the text file in read-only mode by passing the file name, and
mode as arguments to it (Here “r” represents read-only mode)
givenFile = open(inputFile,"r")
• Print it value of the given file.
Example
The following program returns the file not found error if we access an file that doesn’t
exist −
inputFile = "tutorialsPoint.txt"
givenFile = open(inputFile,"r")
print(givenFile)
Output
On executing, the above program will generate the following output −
Traceback (most recent call last):
File "main.py", line 4, in <module>
givenFile = open(inputFile,"r")
FileNotFoundError: [Errno 2] No such file or directory: 'tutorialsPoint.txt'
If these exceptions are not handled, it drives the program into a halt state. Exception
handling in python is required to prevent the program from terminating abruptly. This article
will further explain Exception Handling in Python.
An exception is a class in Python that represents an error. When an exception is raised during the
execution of code, it disrupts the normal flow of the program and can lead to a halt state or even
a crash. To avoid this, it's important to do Exception handling in Python in a way that allows the
program to continue running even if an error occurs.
Exception handling in Python is achieved using the try and except blocks. The try block is used
to enclose the code that may raise an exception, while the except block is used to handle the
exception that may occur. If an exception is raised in the try block, the program jumps to the
except block to handle it, instead of halting the program altogether.
try:
# code that may raise an exception
except:
# code to handle the exception
It's important to note that try and except blocks must be used together in order to handle
exceptions properly. Writing just try or except blocks alone will result in an error.In addition, the
except block can specify the type of exception that it wants to catch.
Before proceeding further, we need to understand what some of the common exceptions that
python throws are.
All the inbuilt exceptions in python are inherited from the common ‘Exception’ class. Some of
the common inbuilt exceptions are:
Exception All exceptions inherit this class as the base class for all exceptions.
Raised when the next() method of an iterator while iteration does not
StopIteration
point to any object
StandardError All exceptions inherit this class except stop StopIteration and SystemExit
ArithmeticError Errors that occur during numeric calculation are inherited by it.
When a calculation exceeds the max limit for a specific numeric data
OverflowError
type
Raised when the end of file is reached, usually occurs when there is no
EOFError
input from input() function
RuntimeError Raised when an error does not fall into any other category
These are just some of the common exceptions in python. To understand more on types of
exceptions check python’s official documentation on exceptions
In the above example, we caught the exception that was being raised in the try block, but the
except blocks are going to catch all the exceptions that try might raise.
Well, it’s considered a good practice to catch specific types of exceptions and handle them
accordingly. And yes, try can have multiple except blocks. We can also use a tuple of values in
an except to receive multiple specific exception types.
Output:
enter a:4
enter b:2
after division 2.0
index error
• In the above code the exceptions raised totally depend upon the input that the user might enter.
Hence if a user enters a value as 0 for ‘b’, the python interpreter will raise a ZeroDivisionError.
• And as the array ‘a’ has a length of 3, and the user is trying to access an element at index 3,
an IndexError will be raised by the python interpreter.
• Each except block has been defined for both the exceptions as one of them receives exceptions
of type IndexError and the other receives of type ZeroDivisionError.
If we want the above snippet to catch exception for both IndexError OR ZeroDivisionError, it
can be re-written as:
Output:
enter a:10
enter b:2
after division 5.0
index error OR zero division error
Note: Only one of the except blocks is triggered when an exception is raised. Consider an
example where we have one except as except IndexError and another as except(IndexError,
ZeroDivisionError) then the one written first will trigger.
Even though exceptions in python are automatically raised in runtime when some error occurs.
Custom and predefined exceptions can also be thrown manually by raising it for specific
conditions or a scenario using the raise keyword. (A custom exception is an exception that a
programmer might raise if they have a requirement to break the flow of code in some specific
scenario or condition) String messages supporting the reasons for raising an exception can also
be provided to these custom exceptions.
For example:
def isStringEmpty(a):
if(type(a)!=str):
raise TypeError('a has to be string')
if(not a):
raise ValueError('a cannot be null')
a.strip()
if(a == ''):
return False
return True
try:
a = 123
print('isStringEmpty:', isStringEmpty(a))
except ValueError as e:
print('ValueError raised:', e)
except TypeError as e:
print('TypeError raised:', e)
Output:
Sometimes you might have a use case where you want to run some specific code only when there
are no exceptions. For such scenarios, the else keyword can be used with the try block. Note that
this else keyword and its block are optional.
Example:
When an exception is not raised, it flows into the optional else block.
try:
b = 10
c = 2
a = b/c
print(a)
except:
print('Exception raised')
else:
print('no exceptions raised')
Output:
5.0
no exceptions raised
In the above code, As both the inputs are greater than 0 which is not a risk
to DivideByZeroException, hence try block won’t raise any exception and hence ‘except’ block
won’t be triggered. And only when the control doesn’t flow to the except block, it flows to
the else block. Further handling can be done inside this else block if there is something you want
to do.
Example:
When an exception is raised, control flows into the except block and not the else block.
try:
b = 10
c = 0
a = b/c
print(a)
except Exception as e:
print('Exception raised:', e)
else:
print('no exceptions raised')
Output:
In the above code, As both the ‘b’ input is 0 which is a risk to DivideByZeroException, hence
the ‘try’ block will raise an exception, and hence the ‘except’ block will be triggered. And now
as there is an exception raised, the control flows to the except block and not to the else block.
Finally is a keyword that is used along with try and except, when we have a piece of code that is
to be run irrespective of if try raises an exception or not. Code inside finally will always run after
try and catch.
Example:
try:
temp = [1, 2, 3]
temp[4]
except Exception as e:
print('in exception block: ', e)
else:
print('in else block')
finally:
print('in finally block')
Output:
In the above code, we’re creating an array with 3 elements, i.e. max index up till 2. But when we
try to access the 4th index, it will raise an exception of index out of range and will be caught in
the except block. But here we need to observe that the finally block has also been triggered.
Example:
Rewriting the above code such that exception is not raised. Where an exception is not raised and
else and finally both are triggered.
Note: else block will always be triggered before finally and finally will always trigger
irrespective of any exceptions raised or not.
try:
temp = [1, 2, 3]
temp[1]
except Exception as e:
print('in exception block: ', e)
else:
print('in else block')
finally:
print('in finally block')
Output:
in else block
in finally block
In the above code, we’re creating an array with 3 elements, i.e. max index up till 2. But when we
try to access the 2nd index, now it will not raise an exception and control will now flow to
another block and then to finally.
But here we need to observe that the finally block has also been triggered even though the
exception was not raised.
• Consider above as a pseudo-code to a program where it checks out items added by the user in
their cart.
• The Checkout method always creates an order id before booking all the items in the cart.
• Assuming itemsInCart contains all the items the user has added to a cart.
• In the checkout experience of an e-commerce website, an orderId is created irrespective of
whether a booking of all items has been a success, failed, or partially failed.
• Hence in the above pseudo-code, we’re creating an orderId using GetOrderIdForBooking() and
assume it returns a random string for each order. BookItems() books all the items for us in
the itemsInCart array.
• If some error occurs while booking items, we have to log the reason for the
exception LogErrorOccuredWhileBooking() does that job for us and if it's successful we have to
log that the booking was successful.
• Now whatever the status of the order is, either way we have to email the status of the order to
the user and that’s what the EmailOrderStatus() does for us.
The above example perfectly fits for an application of try, except or else and finally block as
each block is playing a role that might’ve been difficult to achieve if we didn’t use these blocks.
• If an error occurs while handling something in an except block, the finally block still gives us a
chance to handle the situation our way.
Note: Once an exception/error is raised in the except block, finally block is triggered but the
program still goes into a halt state post to that and the flow is broken.
• But what if an error occurs in the finally block? Let’s orchestrate these series of events in the
following code:
try:
raise Exception("message from try block")
except Exception as e:
print('in except block:', e)
raise Exception("exception raised in except block")
finally:
print("in finally")
raise Exception("exception raised in finally block")
Output:
• Well, the finally block won’t be completed beyond the point where the exception is thrown.
Note that except block won’t be triggered again.
Conclusion
• Exceptions can be expected or unexpected either way they are to be handled as the application
goes into a halt state that most of the applications cannot afford
• Any code that is prone to an exception must be written in try block, if an exception is raised then
the control goes into the except block - provided the except block accepts that specific type of
exception or all exceptions in general.
• If no exception is raised then the code flows to the else block which is optional. Whether an
exception is raised or not control always flows to the finally block which is also optional.
• Syntax in a nutshell:
try:
# Some Code
except:
# Executed if an error is raised by the try block
# Handle exception here
else:
# OPTIONAL & Executed if no exceptions are raised
finally:
# OPTIONAL & will always be executed in the end
1. BaseException:
• Typically, you wouldn't handle this exception directly because it's very broad and could
encompass system-exiting exceptions like SystemExit, KeyboardInterrupt, etc.
2. Exception:
• This is a general-purpose exception that catches most built-in exceptions. You might use
it when you want to handle any unexpected error.
try:
except Exception as e:
3. ArithmeticError:
result = 10 / 0
except ZeroDivisionError:
4. LookupError:
my_list = [1, 2, 3]
try:
except IndexError:
5. AssertionError:
x = 10
try:
except AssertionError:
6. AttributeError:
class MyClass:
pass
obj = MyClass()
try:
except AttributeError:
try:
except EOFError:
8. ImportError:
try:
import non_existent_module
except ImportError:
9. NameError:
try:
print(undefined_variable)
except NameError:
10. TypeError:
try:
except TypeError:
And so on for other exceptions in the hierarchy. These examples demonstrate how different exceptions
can occur in various scenarios and how you can handle them using try and except blocks.
5. Handling Multiple Exceptions
Given a piece of code that can throw any of several different exceptions, and
one needs to account for all of the potential exceptions that could be raised
without creating duplicate code or long, meandering code passages.
If you can handle different exceptions all using a single block of code, they can
be grouped together in a tuple as shown in the code given below :
Code #1 :
try:
client_obj.get_url(url)
except (URLError, ValueError, SocketTimeout):
client_obj.remove_url(url)
The remove_url() method will be called if any of the listed exceptions occurs.
If, on the other hand, if one of the exceptions has to be handled differently,
then put it into its own except clause as shown in the code given below :
Code #2 :
try:
client_obj.get_url(url)
except (URLError, ValueError):
client_obj.remove_url(url)
except SocketTimeout:
client_obj.handle_url_timeout(url)
try:
f = open(filename)
except (FileNotFoundError, PermissionError):
...
Except statement can be re-written as in the code given below. This works
because OSError is a base class that’s common to both
the FileNotFoundError and PermissionError exceptions.
Code #4 :
try:
f = open(filename)
except OSError:
...
Although it’s not specific to handle multiple exceptions per se, it is worth
noting that one can get a handle to the thrown exception using them as a
keyword as shown in the code given below.
Code #5 :
try:
f = open(filename)
except OSError as e:
if e.errno == errno.ENOENT:
logger.error('File not found')
elif e.errno == errno.EACCES:
logger.error('Permission denied')
else:
logger.error('Unexpected error: % d', e.errno)
The e variable holds an instance of the raised OSError. This is useful if the
exception has to be invested further, such as processing it based on the value
of the additional status code. The except clauses are checked in the order
listed and the first match executes.
Code #6 : Create situations where multiple except clauses might match
f = open('missing')
Output :
Traceback (most recent call last):
File "", line 1, in
FileNotFoundError: [Errno 2] No such file or directory: 'miss
try:
f = open('missing')
except OSError:
print('It failed')
except FileNotFoundError:
print('File not found')
Output :
Failed
Here the except FileNotFoundError clause doesn’t execute because
the OSError is more general, matches the FileNotFoundError exception, and
was listed first.
6. Raise
In Python, the raise statement is used to explicitly raise an exception or error. This can
be done to handle exceptional situations in your code, such as when a condition occurs
that warrants an error being reported.
Where:
For example, you might raise a “ValueError” when a function receives an invalid
argument:
def divide(x, y):
if y == 0:
return x / y
try:
result = divide(10, 0)
except ValueError as e:
In this example, if the divisor y is 0, the raise statement is triggered, raising a ValueError
with the specified error message. Then, the exception is caught in the except block, and
the error message is printed.
You can also raise custom exceptions by defining your own exception classes. This can
be useful for handling specific errors in your application. Here's an example:
class MyCustomError(Exception):
pass
def my_function():
try:
my_function()
except MyCustomError as e:
In this case, we define a custom exception class MyCustomError, and then raise an instance
of it within my_function(). When the exception is raised, it's caught in the except block,
and the error message is printed.
Using raise allows you to control the flow of your program when unexpected situations
occur, providing a way to handle errors gracefully and provide meaningful feedback to
users or developers.
7. Assert
In Python, the assert statement is used as a debugging aid to test a condition. It ensures
that the condition specified is true. If the condition is false, it raises an AssertionError
exception with an optional error message.
return x / y
print(result)
In this example, the assert statement checks if the divisor y is not equal to zero. If y is
zero, it raises an AssertionError with the message "Divisor cannot be zero". This helps to
catch potential bugs or unexpected conditions during development and testing.
It's worth noting that assert statements can be disabled globally by running Python with
the -O option, or individually using the -oo option. In optimized mode, assertions are
ignored and not evaluated. Therefore, it's typically used during development and
debugging, rather than in production code.