When we write Python programs, we expect the instructions in our code to execute correctly and produce the required result. However, programs do not always behave as expected. A spelling mistake, an invalid operation, incorrect data, or an unexpected situation can cause Python to stop normal execution and report a problem.
These problems are broadly discussed as errors and exceptions. Understanding them is one of the most important steps toward writing reliable Python programs.
For example, consider this simple program:
print("Hello Python")
This program executes successfully because the syntax is valid and Python knows exactly what operation needs to be performed.
Now consider:
print("Hello Python"
Here, a closing parenthesis is missing. Python cannot correctly understand the structure of the statement, so it reports a problem before the program can execute normally.
Another example is:
result = 10 / 0
The syntax of this statement is valid, but the operation itself is invalid because division by zero is not allowed. Python therefore reports an exception while the program is running.
These two examples demonstrate an important idea: not all programming problems occur at the same stage.
Some problems are detected when Python is trying to understand the code, while others occur during execution.
An error is a problem in a Python program that prevents the program from behaving as intended. Depending on the type of problem, Python may stop execution and display an error message.
For beginners, the word error is often used for almost every problem encountered while programming. This is understandable because Python displays an error message when something goes wrong.
However, Python provides more specific categories of problems, including syntax errors and exceptions.
Consider:
if 10 > 5
print("Yes")
The statement is missing a colon after the condition.
Python cannot correctly interpret the structure, so it reports a syntax-related problem.
Now consider:
number = 10
result = number / 0
This code has valid Python syntax. Python can understand the statements, but when it tries to perform the division, it encounters an invalid operation.
This results in a ZeroDivisionError.
Therefore, when learning Python error handling, it is useful to distinguish between problems in the structure of the code and problems that occur while the code is executing.
An exception is an event that occurs during program execution when Python encounters a situation that prevents the current operation from proceeding normally.
For example:
number = 10
result = number / 0
Python attempts to perform the calculation:
10 / 0
But division by zero is not a valid arithmetic operation. Python raises:
ZeroDivisionError
Another example:
age = int("twenty")
Python attempts to convert the string:
"twenty"
into an integer. Because the string does not represent a valid integer, Python raises:
ValueError
Another example:
numbers = [10, 20, 30]
print(numbers[5])
The list contains indexes from 0 to 2, so index 5 does not exist. Python raises:
IndexError
These are examples of exceptions because the problems occur while Python is executing the program.
The terms error and exception are sometimes used interchangeably in beginner-level programming, but understanding the distinction is useful.
| Concept | Meaning |
|---|---|
| Error | A general term for a problem that causes a program to fail or behave incorrectly. |
| Exception | An event raised during execution when Python encounters an unexpected or invalid situation. |
| Syntax Error | A problem with the structure or syntax of Python code. |
| Runtime Exception | A problem that occurs while valid Python code is executing. |
The most important point is that Python provides mechanisms for detecting and handling exceptions so that a program does not necessarily have to terminate abruptly whenever an expected problem occurs.
There are many reasons why a Python program may encounter a problem.
Some common causes include:
For example, in Data Analytics, a program may expect a numerical value but receive text from a CSV file.
sales = "5000"
average = sales / 10
The variable contains a string rather than a number. Python cannot perform the requested division between the string and the integer, so an exception occurs.
Data Analytics programs frequently work with data coming from files, databases, APIs, forms, and external systems. Because external data cannot always be guaranteed to be perfect, understanding exceptions becomes especially important.
When an exception occurs, Python generally provides useful information about the problem.
Consider:
number = 10
result = number / 0
Python reports an exception that identifies:
ZeroDivisionError
It also provides a message explaining the immediate problem.
Similarly:
numbers = [10, 20, 30]
print(numbers[5])
Python reports:
IndexError
The message indicates that the requested list index is outside the available range.
These messages are extremely useful during debugging.
When an exception occurs, do not immediately assume that the Python interpreter is wrong. Read the exception type and the accompanying message carefully. They often provide the first clue needed to locate the problem.
Python commonly displays a traceback when an exception occurs.
A traceback helps identify where the problem happened in the program.
For example:
def calculate_average(total, count):
return total / count
total = 500
count = 0
average = calculate_average(total, count)
When the program reaches:
total / count
Python encounters division by zero.
The traceback can show the sequence of calls that led to the exception and identify the line where the exception occurred.
This becomes increasingly important as programs become larger.
Imagine a Data Analytics application containing several functions:
load_data()
↓
clean_data()
↓
calculate_metrics()
↓
generate_report()
If an exception occurs inside calculate_metrics(), the traceback can help identify how execution reached that point.
Learning to read tracebacks is therefore an essential Python programming skill.
Let’s look at several basic examples.
ZeroDivisionError
result = 100 / 0
Python cannot divide a number by zero.
NameError
print(customer_name)
If customer_name has not been defined, Python cannot find the variable.
TypeError
result = "100" + 50
The operation attempts to combine incompatible types in a way Python does not allow.
ValueError
number = int("hello")
The value cannot be converted into an integer.
IndexError
items = [10, 20, 30]
print(items[10])
The requested index does not exist.
KeyError
student = {
"name": "Rahul"
}
print(student["age"])
The dictionary does not contain the requested key.
These examples show why exceptions are important. The code may be syntactically understandable, but the operation can still fail because of the actual values or state encountered during execution.
Imagine a program that reads sales data from a file.
sales_file = open(
"sales.csv"
)
If the file does not exist, the program may stop with an exception.
Now imagine a web application where a user enters their age.
age = int(
input("Enter your age: ")
)
If the user enters:
twenty
the conversion fails.
Similarly, imagine a Data Analytics program receiving data from an API. A field expected to contain a number might instead contain an empty value or text.
Without appropriate handling, one unexpected value could interrupt the entire processing workflow.
Exception handling allows developers to anticipate certain problems and define what the program should do when they occur.
The basic idea is:
Normal Operation
↓
Unexpected Situation
↓
Exception
↓
Handle the Exception
↓
Continue or Exit Gracefully
Instead of allowing every unexpected situation to terminate the program without explanation, we can design the application to respond appropriately.
Exception handling is particularly important for Data Analytics because analytical programs often depend on external data.
For example, suppose we read a column containing ages:
ages = [
"21",
"25",
"30",
"unknown",
"40"
]
A program attempting to convert every value directly into an integer may encounter a ValueError when it reaches:
"unknown"
Another example is a dataset containing missing values.
A calculation might unexpectedly encounter an empty or invalid value.
Other possible sources of exceptions include:
This is why exception handling is not simply a topic for avoiding beginner mistakes. It is an important part of building reliable data-processing applications.
It is useful to understand the basic difference between a syntax problem and a runtime exception.
Consider:
print("Hello"
Python cannot properly interpret the statement because the syntax is incomplete.
Now consider:
number = 10
result = number / 0
The syntax is valid, but the operation fails during execution.
Therefore:
Syntax Problem
↓
Python cannot properly interpret the code
Runtime Exception
↓
Python understands the code
but encounters a problem while executing it
This distinction will become important when we start learning how try, except, else, and finally work.
A common beginner mistake is to think that exception handling simply means hiding error messages.
That is not the purpose.
Good exception handling should make a program more reliable and provide a meaningful response when something unexpected happens.
For example, if a user enters an invalid age, a good program might explain that the input is invalid and request another value.
In a Data Analytics application, if a particular input file is missing, the application might provide a clear message indicating which file is unavailable rather than simply crashing without context.
The goal is not to pretend that errors do not exist. The goal is to handle expected problems intelligently.
ZeroDivisionError, NameError, TypeError, ValueError, IndexError, and KeyError.try, except, else, and finally statements.In the next section, we will explore the major types of Python errors and exceptions in greater detail, including SyntaxError, NameError, TypeError, ValueError, IndexError, KeyError, and ZeroDivisionError, with practical examples.
Python programs can fail for different reasons, and understanding the type of problem is important because each problem tells us something different about what went wrong. Some problems are related to the structure of the code, while others occur when the program is executing a valid statement with unexpected data or conditions.
In this section, we will examine the most important Python errors and exceptions that beginners and Data Analytics students should understand. These include SyntaxError, NameError, TypeError, ValueError, ZeroDivisionError, IndexError, KeyError, and AttributeError.
Understanding these exceptions will make debugging much easier and will prepare you for using Python’s exception-handling mechanisms.
A SyntaxError occurs when Python cannot understand the structure of the code because it does not follow Python’s syntax rules.
For example:
print("Hello"
The closing parenthesis is missing. Python cannot correctly interpret the statement.
Another example:
if age > 18
print("Adult")
The colon after the condition is missing.
The correct version is:
if age > 18:
print("Adult")
Syntax errors are generally detected before the affected code can execute normally.
This makes them different from exceptions such as ValueError or ZeroDivisionError, which can occur while a valid program is running.
Python uses indentation to define blocks of code. Incorrect indentation can therefore cause an error.
For example:
if age > 18:
print("Adult")
The print() statement should be indented.
Correct:
if age > 18:
print("Adult")
Incorrect indentation can result in an IndentationError.
This is especially important for beginners because indentation in Python is not merely a formatting preference. It is part of the language syntax.
A NameError occurs when Python cannot find a name that the program is trying to use.
For example:
print(customer_name)
If customer_name has not been defined, Python cannot determine what it refers to.
Another common example is a spelling mistake:
customer = "Rahul"
print(custmer)
The variable was created as:
customer
but the program attempts to access:
custmer
Because these are different names, Python raises a NameError.
The correct code is:
customer = "Rahul"
print(customer)
Name errors are often easy to fix once you carefully check variable names and spelling.
A TypeError occurs when an operation or function is applied to an object of an inappropriate type.
For example:
result = "100" + 50
Here, one value is a string and the other is an integer. Python cannot perform this particular addition operation between the two types.
Another example:
name = "Rahul"
print(name + 25)
Again, the operation attempts to combine incompatible types.
We can fix the problem by converting the integer to a string:
name = "Rahul"
print(name + str(25))
Or, if the values are intended to be numerical, we can convert the string into an integer:
number = "100"
result = int(number) + 50
print(result)
Output:
150
TypeError is particularly common when processing external data because data may not always have the type we expect.
A ValueError occurs when a function receives a value of the correct general type but the value itself is inappropriate for the requested operation.
For example:
number = int("hello")
The int() function expects a string representing a valid integer. The value "hello" is a string, but it does not represent a valid integer.
Therefore, Python raises a ValueError.
Consider another example:
age = int(
input("Enter your age: ")
)
If the user enters:
twenty
the conversion fails.
This is a very common real-world situation.
The user may enter unexpected input, or an external data source may contain values that cannot be converted into the required format.
The difference between TypeError and ValueError is important.
| Exception | Basic Meaning | Example |
|---|---|---|
TypeError |
Wrong or incompatible type for an operation | "100" + 50 |
ValueError |
Correct general type, but inappropriate value | int("hello") |
A simple way to remember this is:
TypeError
"What type of object is this?"
ValueError
"Is this value valid for the operation?"
A ZeroDivisionError occurs when a program attempts to divide a number by zero.
result = 100 / 0
This operation is mathematically undefined, so Python raises:
ZeroDivisionError
The same issue can occur with variables:
total_sales = 10000
number_of_customers = 0
average_sales = (
total_sales
/ number_of_customers
)
This is particularly relevant to Data Analytics.
Suppose we calculate average sales per customer:
average_sales = (
total_sales
/ number_of_customers
)
If there are no customers, the denominator becomes zero.
A robust analytical program should therefore consider the possibility of zero before performing the calculation.
An IndexError occurs when we attempt to access a sequence using an index that does not exist.
Consider:
numbers = [
10,
20,
30
]
The valid indexes are:
0
1
2
Therefore:
print(numbers[0])
print(numbers[1])
print(numbers[2])
works correctly.
But:
print(numbers[3])
raises an IndexError because index 3 does not exist.
Another example:
students = [
"Rahul",
"Priya",
"Amit"
]
print(students[10])
The list contains only three elements, so index 10 is outside the valid range.
Index errors are common when working with lists, tuples, and other sequence-like objects.
A KeyError occurs when we attempt to access a dictionary using a key that does not exist.
For example:
student = {
"name": "Rahul",
"age": 21
}
print(student["city"])
The dictionary contains:
name
age
but it does not contain:
city
Therefore, Python raises a KeyError.
This is especially relevant in Data Analytics because dictionaries are frequently used to represent records.
For example:
customer = {
"name": "Rahul",
"sales": 50000,
"region": "North"
}
Trying to access:
customer["email"]
will cause a KeyError if the email field is absent.
Later, when learning exception handling, we will see how to deal with situations like this safely.
An AttributeError occurs when an object does not have the attribute or method that we are trying to access.
For example:
name = "Rahul"
print(name.age)
A string object does not have an age attribute, so Python raises an AttributeError.
Another example:
class Student:
def __init__(self, name):
self.name = name
student = Student("Rahul")
print(student.age)
The Student object contains:
name
but it does not contain:
age
Therefore, Python raises an AttributeError.
Python programs frequently work with files, especially in Data Analytics.
For example:
file = open(
"sales.csv",
"r"
)
If the file does not exist at the specified location, Python can raise a FileNotFoundError.
This is a common situation when working with:
For example:
file = open(
"missing_sales.csv",
"r"
)
If the file is unavailable, the program cannot complete the requested operation.
Later, exception handling can be used to provide a more useful response instead of allowing the application to terminate unexpectedly.
A single program can potentially contain several different types of exceptions.
For example:
data = {
"sales": "5000"
}
customers = 0
sales = int(
data["sales"]
)
average = (
sales / customers
)
The conversion of "5000" is valid, but the division by zero is not.
Therefore, the program may encounter a ZeroDivisionError.
If the data instead contained:
data = {
"sales": "unknown"
}
then:
int(data["sales"])
would result in a ValueError.
This demonstrates why programs need to consider the actual data and conditions encountered during execution.
Imagine a simple analytical workflow:
Read File
↓
Load Data
↓
Clean Data
↓
Transform Data
↓
Calculate Metrics
↓
Generate Report
Each stage can potentially encounter a different exception.
Read File:
The file may not exist, resulting in a FileNotFoundError.
Load Data:
The data may have an unexpected format.
Clean Data:
A conversion may fail with a ValueError.
Transform Data:
An operation may receive an incompatible type, resulting in a TypeError.
Calculate Metrics:
A calculation may attempt division by zero.
Generate Report:
An expected dictionary key or object attribute may be missing.
This is why understanding individual exception types is an important foundation for building reliable analytical programs.
| Exception | Typical Cause |
|---|---|
SyntaxError |
Invalid Python syntax |
IndentationError |
Incorrect indentation |
NameError |
Name or variable is not defined |
TypeError |
Invalid or incompatible object type |
ValueError |
Invalid value for an operation |
ZeroDivisionError |
Division by zero |
IndexError |
Sequence index does not exist |
KeyError |
Dictionary key does not exist |
AttributeError |
Object does not have requested attribute |
FileNotFoundError |
Requested file cannot be found |
When Python displays an exception, the first useful step is to identify its type.
For example:
ValueError
tells us that the problem is related to an inappropriate value.
If we see:
IndexError
we should immediately check whether the program is trying to access an invalid sequence index.
If we see:
KeyError
we should inspect the dictionary key being requested.
If we see:
TypeError
we should examine the types of the objects involved in the operation.
This habit makes debugging faster because the exception type narrows down the possible causes.
SyntaxError indicates invalid Python syntax.IndentationError occurs when Python indentation rules are violated.NameError occurs when Python cannot find a requested name.TypeError generally indicates an inappropriate or incompatible type.ValueError indicates an inappropriate value.ZeroDivisionError occurs when division by zero is attempted.IndexError occurs when a sequence index does not exist.KeyError occurs when a requested dictionary key is missing.AttributeError occurs when an object does not have the requested attribute or method.FileNotFoundError can occur when a requested file is unavailable.In the next section, we will look more closely at what happens when an exception interrupts normal program execution and how Python’s exception mechanism allows us to control that flow before introducing the full try-except structure.
So far, we have learned what errors and exceptions are and examined several common Python exceptions such as ValueError, TypeError, IndexError, KeyError, and ZeroDivisionError. The next important concept is understanding what actually happens to a Python program when an exception occurs.
Normally, Python executes statements sequentially, generally from top to bottom. If an exception occurs and nothing handles it, normal execution stops at that point. Python then reports the exception and provides a traceback that helps identify where the problem occurred.
Consider this example:
print("Step 1")
number = 10 / 0
print("Step 2")
The first statement executes successfully:
Step 1
Then Python reaches:
number = 10 / 0
At this point, Python encounters a ZeroDivisionError. The program cannot continue normally from that statement.
Therefore:
print("Step 2")
is not executed.
The basic flow is:
Statement 1
↓
Statement 2
↓
Exception occurs
↓
Normal execution stops
↓
Python reports exception
This behavior is fundamental to understanding exception handling.
Consider a program without an exception:
print("Start")
number = 10
print(number)
print("End")
The execution flow is straightforward:
Start
↓
number = 10
↓
print(number)
↓
End
Now introduce an exception:
print("Start")
number = 10 / 0
print("End")
The flow changes:
Start
↓
10 / 0
↓
ZeroDivisionError
↓
Program stops
The exception changes the normal flow of execution.
This is exactly why exception handling exists. It allows us to define what should happen when a particular problem occurs.
When Python encounters an exceptional situation, it raises an exception.
For example:
number = 10 / 0
causes Python to raise a ZeroDivisionError.
Similarly:
value = int("hello")
causes Python to raise a ValueError.
The important idea is:
Unexpected situation
↓
Exception is raised
↓
Python looks for a way to handle it
↓
If no handler is available
↓
Program terminates with traceback
In later sections, we will use try and except to provide that handling mechanism.
Suppose we have:
print("A")
x = 20
print("B")
result = 10 / 0
print("C")
print("D")
The output before the exception is:
A
B
Then the exception occurs.
C and D are not printed because execution has stopped.
This is important in larger applications.
Imagine a Data Analytics workflow:
Load CSV
↓
Clean Data
↓
Calculate Metrics
↓
Create Visualization
↓
Generate Report
If an unhandled exception occurs during data cleaning, the later stages may never execute.
For example:
Load CSV
↓
Clean Data
↓
ValueError
↓
STOP
X
Calculate Metrics
X
Create Visualization
X
Generate Report
This can be a serious problem in automated analytical workflows.
Suppose we are processing thousands of customer records.
customers = [
"100",
"250",
"unknown",
"500",
"700"
]
If the program assumes every value is a valid integer:
for customer in customers:
number = int(customer)
print(number)
the program will eventually reach:
"unknown"
and raise a ValueError.
Without appropriate handling, processing stops at that point.
That means even the later values may not be processed.
In real Data Analytics work, data is often imperfect. A dataset may contain:
A robust program needs a strategy for dealing with such situations.
Exception handling allows us to change what happens when a problem occurs.
Instead of:
Normal execution
↓
Exception
↓
Program stops
we can design a controlled flow:
Normal execution
↓
Potentially risky operation
↓
Exception occurs
↓
Handle exception
↓
Continue or respond appropriately
This does not mean that every exception should simply be ignored.
The correct response depends on the application.
For example, if a user enters an invalid age, we may ask for the value again.
If a required file is missing, we may display a clear message and stop the operation.
If an optional record contains invalid data, we may skip that record and continue processing other records.
Therefore, exception handling is about controlled behavior, not simply hiding errors.
Python provides the try statement to identify code that may generate an exception.
A basic structure looks like:
try:
risky_operation()
For example:
try:
result = 10 / 0
The try block tells Python that the enclosed code is being executed in a context where an exception may need to be handled.
However, try by itself does not provide a complete exception-handling solution.
We normally combine it with except.
The except block defines what should happen when a matching exception occurs.
For example:
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero")
Now the program does not simply terminate with an unhandled exception.
Instead, Python detects the ZeroDivisionError and executes the corresponding except block.
The conceptual flow becomes:
try
↓
10 / 0
↓
ZeroDivisionError
↓
except ZeroDivisionError
↓
print message
This is the foundation of Python exception handling.
Consider user input:
age = int(
input("Enter age: ")
)
If the user enters:
twenty
Python raises ValueError.
We can handle it using:
try:
age = int(
input("Enter age: ")
)
except ValueError:
print(
"Please enter a valid number"
)
The important point is that the exception is not being ignored. The program is responding to the specific problem.
A single piece of code may potentially produce different exceptions.
For example:
value = input(
"Enter a number: "
)
number = int(value)
result = 100 / number
This code can potentially encounter:
ValueError if the user enters non-numeric textZeroDivisionError if the user enters zeroWe can handle these separately:
try:
value = input(
"Enter a number: "
)
number = int(value)
result = 100 / number
except ValueError:
print(
"Please enter a valid number"
)
except ZeroDivisionError:
print(
"Number cannot be zero"
)
This demonstrates an important principle: different problems can require different responses.
Beginners sometimes try to handle every possible problem using a very broad exception handler.
For example:
try:
result = 100 / number
except:
print("Something went wrong")
Although this may catch many problems, it does not clearly identify what went wrong.
It is generally better to handle expected exception types explicitly:
try:
result = 100 / number
except ZeroDivisionError:
print(
"Cannot divide by zero"
)
This makes the program easier to understand and debug.
Specific exception handling also allows us to provide an appropriate response for each situation.
Let’s consider a simple data-processing example.
values = [
"100",
"200",
"invalid",
"400"
]
for value in values:
number = int(value)
print(number)
The program successfully processes:
100
200
Then it encounters:
invalid
and raises a ValueError.
As a result, the remaining value may not be processed.
A controlled approach can identify the invalid record and respond appropriately.
For example, conceptually:
Read value
↓
Try conversion
↓
Valid?
↙ ↘
Yes No
↓ ↓
Process Handle
invalid value
This type of logic is common when working with real-world data.
Exceptions can also travel through function calls.
Consider:
def divide(a, b):
return a / b
def calculate():
return divide(10, 0)
result = calculate()
The division occurs inside divide(), but the exception can affect the caller as well.
This is where the traceback becomes useful. It can show the chain of function calls that led to the exception.
Conceptually:
main program
↓
calculate()
↓
divide()
↓
ZeroDivisionError
Python can trace this path to show where the exception originated.
Later, exception handling can be placed at an appropriate level in the application depending on where the problem should be handled.
Python exceptions are objects. This means an exception can contain information about the problem.
For example, an exception can have a message describing what happened.
We can capture an exception object using:
try:
number = int("hello")
except ValueError as error:
print(error)
Here:
error
refers to the exception object.
This allows a program to inspect or display information associated with the exception.
For example, the message can help developers understand why the conversion failed.
If an exception is not handled where it occurs, Python can propagate it back through the calling functions.
Consider:
def first():
return second()
def second():
return 10 / 0
first()
The exception occurs inside second().
If it is not handled there, it can propagate back through first().
If no suitable handler is found, the program eventually terminates with a traceback.
The basic concept is:
Exception occurs
↓
Current function
↓
Caller
↓
Higher-level caller
↓
Suitable handler?
↙ ↘
Yes No
↓ ↓
Handle Program
exception terminates
Understanding this concept becomes very useful when working with larger Python applications.
Not every exception needs to be handled immediately where it occurs.
Sometimes the function that detects the problem does not have enough information to decide what to do.
For example, a low-level function may detect that a file could not be opened, while a higher-level application may decide whether to ask the user for another file or terminate the workflow.
This means exception handling should be designed according to the responsibility of each part of the application.
A useful principle is:
Handle an exception where you can meaningfully respond to it.
try block identifies code where an exception may occur.except block provides a response for a matching exception.In the final part of this lesson, we will apply these concepts through practical examples, debugging exercises, common mistakes, interview questions, and a complete review of Python errors and exceptions.
By this point, you understand what errors and exceptions are, why they occur, how they interrupt normal program execution, and why exception handling is important. In this final section, we will bring these concepts together through practical examples and exercises.
The objective is not simply to memorize names such as ValueError or TypeError. A good Python programmer should be able to look at a problem, identify the likely exception, understand why it occurred, and decide how the application should respond.
Let’s begin with a simple function that divides two numbers.
def divide(a, b):
return a / b
print(divide(100, 5))
This works correctly and returns:
20.0
But what happens when the second value is zero?
print(divide(100, 0))
Python raises a ZeroDivisionError.
A safer approach is to handle the expected exception:
def divide(a, b):
try:
return a / b
except ZeroDivisionError:
return "Cannot divide by zero"
print(divide(100, 5))
print(divide(100, 0))
Now the function can provide a meaningful response instead of allowing the exception to terminate the program.
User input is another common source of exceptions.
age = int(
input("Enter your age: ")
)
print(age)
If the user enters:
25
the program works.
But if the user enters:
twenty-five
Python raises a ValueError.
We can handle this situation:
try:
age = int(
input("Enter your age: ")
)
print(
"Your age is:",
age
)
except ValueError:
print(
"Please enter a valid number."
)
This is a simple example of designing a program to handle unexpected user input.
Suppose the user enters a number and we divide 100 by that number.
try:
number = int(
input("Enter a number: ")
)
result = 100 / number
print(result)
except ValueError:
print(
"Please enter a valid integer."
)
except ZeroDivisionError:
print(
"Zero is not allowed."
)
There are two possible problems:
Each exception gets its own response.
This is much better than giving the same generic message for every possible problem.
Now consider a simple Data Analytics situation.
sales = [
"1000",
"2500",
"invalid",
"4000",
"5000"
]
Suppose we want to convert every value into a number.
for value in sales:
number = int(value)
print(number)
The program will process the first two values but fail when it reaches:
"invalid"
because the value cannot be converted into an integer.
We can handle the problem during processing:
sales = [
"1000",
"2500",
"invalid",
"4000",
"5000"
]
for value in sales:
try:
number = int(value)
print(number)
except ValueError:
print(
"Invalid sales value:",
value
)
Now the invalid record can be identified while the remaining records continue to be processed.
This illustrates a very important real-world use of exception handling in Data Analytics.
Files are another common source of exceptions.
Consider:
file = open(
"sales.csv",
"r"
)
If the file does not exist, Python may raise a FileNotFoundError.
We can respond appropriately:
try:
file = open(
"sales.csv",
"r"
)
data = file.read()
file.close()
except FileNotFoundError:
print(
"Sales file was not found."
)
This provides a meaningful response to the user or developer.
Later, when learning file handling in greater depth, we will learn better patterns for automatically managing files. For now, the important concept is recognizing that file operations can generate exceptions.
Suppose we have customer data:
customer = {
"name": "Rahul",
"sales": 50000,
"region": "North"
}
If we access:
print(customer["email"])
Python raises a KeyError because the key does not exist.
We can handle it:
try:
email = customer["email"]
print(email)
except KeyError:
print(
"Email information is unavailable."
)
This can be useful when processing records where some fields may be missing.
Consider:
students = [
"Rahul",
"Priya",
"Amit"
]
The valid indexes are:
0
1
2
Attempting:
print(students[5])
produces an IndexError.
We can handle it:
try:
print(students[5])
except IndexError:
print(
"Student index does not exist."
)
However, exception handling should not always replace good programming practices. In many situations, checking the length of a list before accessing an index may be more appropriate.
Suppose we want to create a function that accepts marks.
def calculate_grade(marks):
if marks < 0 or marks > 100:
raise ValueError(
"Marks must be between 0 and 100."
)
if marks >= 90:
return "A+"
elif marks >= 80:
return "A"
elif marks >= 70:
return "B"
elif marks >= 60:
return "C"
else:
return "F"
The function validates the input before performing the calculation.
We can use it with:
try:
marks = int(
input("Enter marks: ")
)
grade = calculate_grade(marks)
print("Grade:", grade)
except ValueError as error:
print(error)
This example combines several concepts:
Identify the exception that will occur:
number = 10
print(number / 0)
Answer:
ZeroDivisionError
The denominator is zero.
Identify the problem:
age = int("twenty")
Answer:
ValueError
The string cannot be converted into an integer.
Identify the exception:
numbers = [10, 20, 30]
print(numbers[10])
Answer:
IndexError
The requested index does not exist.
Identify the exception:
student = {
"name": "Rahul"
}
print(student["marks"])
Answer:
KeyError
The dictionary does not contain the marks key.
Identify the exception:
result = "100" + 50
Answer:
TypeError
The operation attempts to combine incompatible types.
Create a function called:
safe_integer()
It should accept a value and attempt to convert it into an integer.
For example:
safe_integer("100")
should return:
100
While:
safe_integer("hello")
should provide a meaningful response rather than crashing.
Create a function:
safe_average(total, count)
It should calculate:
total / count
but handle the situation where count is zero.
Test it using:
safe_average(1000, 10)
safe_average(1000, 0)
Create a function that accepts a student’s marks.
The function should:
Test it with:
85
105
-10
"hello"
1. Ignoring the actual exception type
Beginners sometimes use a generic handler for every possible problem.
try:
risky_code()
except:
print("Error")
This may hide useful information.
When possible, handle expected exceptions specifically.
2. Using exception handling for every situation
Exception handling should not replace normal validation and logical checks.
For example, if you can easily check whether a list is empty before accessing it, that may be clearer than deliberately causing an IndexError and then catching it.
3. Ignoring exceptions silently
Code such as:
try:
risky_operation()
except:
pass
can make debugging extremely difficult because the program hides the problem without explaining what happened.
4. Giving unclear messages
A useful error response should help the user or developer understand what went wrong.
For example:
"Invalid input"
may be less useful than:
"Age must be a whole number."
1. What is an exception in Python?
An exception is an event that occurs during program execution when Python encounters an unexpected or invalid situation.
2. What is the difference between an error and an exception?
Error is a general term for a problem in a program, while an exception specifically refers to an exceptional event raised during execution.
3. What is a SyntaxError?
A SyntaxError occurs when Python cannot correctly interpret the syntax or structure of the code.
4. What is a ValueError?
A ValueError occurs when an operation receives a value that is inappropriate for that operation.
5. What is a TypeError?
A TypeError occurs when an operation is applied to an inappropriate or incompatible type.
6. What is ZeroDivisionError?
It occurs when a program attempts to divide a number by zero.
7. What is IndexError?
It occurs when a sequence is accessed using an index that does not exist.
8. What is KeyError?
It occurs when a dictionary is accessed using a key that does not exist.
9. What is a traceback?
A traceback is information provided by Python showing the sequence of calls and location associated with an exception.
10. Why is exception handling important?
It allows programs to respond appropriately to expected exceptional situations instead of terminating unexpectedly.
| Concept | Meaning |
|---|---|
| Error | General problem in a program |
| Exception | Exceptional event during execution |
| SyntaxError | Invalid Python syntax |
| NameError | Name is not defined |
| TypeError | Invalid or incompatible type |
| ValueError | Invalid value |
| ZeroDivisionError | Division by zero |
| IndexError | Invalid sequence index |
| KeyError | Missing dictionary key |
| AttributeError | Missing object attribute |
| FileNotFoundError | Requested file is unavailable |
Python errors and exceptions are an unavoidable part of programming. The important skill is not trying to eliminate every possible error, but understanding why problems occur and designing programs that respond appropriately.
In this lesson, we learned that syntax problems occur when Python cannot correctly understand the structure of the code, while exceptions generally occur during execution when an unexpected situation is encountered.
We explored important exceptions including:
SyntaxError
IndentationError
NameError
TypeError
ValueError
ZeroDivisionError
IndexError
KeyError
AttributeError
FileNotFoundError
We also learned that an unhandled exception interrupts normal program execution. Python reports the exception and provides a traceback that helps developers locate the problem.
Most importantly, we introduced the basic idea of exception handling using:
try
except
These mechanisms allow developers to define how a program should respond to expected exceptional situations.
For Data Analytics, this knowledge is particularly valuable because analytical programs frequently work with external data. Files can be missing, values can have unexpected formats, dictionary fields can be absent, and numerical calculations can encounter invalid conditions.
A professional Python programmer therefore needs to develop the habit of reading exception messages, understanding tracebacks, identifying the correct exception type, and deciding whether the problem should be corrected, reported, skipped, or handled by the application.
The next lesson will go deeper into the actual Python exception-handling structure, including try, except, else, and finally, and how these blocks work together in real programs.