Back to blog

Python Errors and Exceptions: An Ultimate Guide to Different Types and Solutions

In this article, we’ll explore the different kinds of errors and exceptions, what causes them, and provide solutions to solving them. No more headaches and cursing your code until it gets scared and starts working – master the language of Python to understand precisely what it wants from you.

Zilvinas Tamulis

Feb 05, 2024

6 min read

Python Errors and Exceptions

What is the difference between Python errors and exceptions?

The terms errors and exceptions are used interchangeably when talking about Python. They refer to any kind of mistake or issue that prevents the code from running successfully. While they’ll often mean the same thing, there are a few differences between them.

Errors refer to a broad definition of issues when running Python code. They can range from simple mistakes where you’ve forgotten to put a bracket to runtime errors that indicate a bigger problem, like a missing library. An error prevents your script from running smoothly, so if you didn’t get the desired result, you probably got an error.

Exceptions refer to runtime errors in particular. They are events that occur during the execution of a program that disrupt the normal flow of the program’s instructions. Unlike errors, they don’t mean that the code must stop completely. Python offers the ability to write further instructions to handle the exception and continue running the program smoothly.

What are the different types of Python errors?

Python errors come in many different shapes and sizes, but they can all be categorized into three distinct types: syntax errors, logical errors, and runtime errors (exceptions).

  • Syntax errors occur when your code doesn’t meet the Python syntax rules. This can be a missing parenthesis, an extra symbol, too many quotation marks, etc. They happen due to human mistakes, so there’s no need to panic – the interpreter is simply confused about what you want to do. It will not run the code until you find and fix the issue. Example:
# SyntaxError - missing second quotation mark (")
print("Hello world!)
  • Logical errors happen when everything goes smoothly, but the outcome isn’t as expected. These don’t produce any warnings; the code will execute as it’s told to do without issues. Avoiding logical errors requires a keen eye and plenty of automated tests to ensure you get precisely what you want. Example:
# Expected result: 8. Code returns 12, because a plus sign is used instead of a minus
result = 10 + 2
print(result)
  • Runtime errors, also known as exceptions, occur during the execution of a program. They check if all conditions of a well-structured code are met and watch if any unexpected events occur. Python has many built-in exceptions that you’ll most likely run into, as well as the ability to write user-defined exceptions. Fixing them requires modifying your code to meet these requirements to run the program smoothly. You may also write exception handlers to execute specific actions when an exception occurs to ensure your application runs smoothly and doesn’t crash. Example:
# NameError - "id" was not defined as a variable anywhere in the code
result = 10 + id
print(result)

Regardless of which error you face, they are detrimental if you want to write robust code and should be handled immediately. Syntax and logic errors require you to fix them manually – either by hand or by running tests to test all possible outcomes. 

Runtime errors can be dealt with more cleanly and concisely through exception handling. They can be true saviors of your code, as they won’t stop your application from running and will execute specific actions when troubles occur. Read on to learn more about them.

What are Python exceptions?

When a Python script encounters an error, it raises an exception. Exceptions are used to handle errors or unexpected situations in a program, preventing it from crashing and providing a way to handle errors in a controlled manner.

How do you handle Python exceptions?

The most common way of Python exception handling is the try-except method. A part of a code that may raise an exception is “tested” with a try clause, and if it returns an exception, the except block will run instead. Here’s a simple example:

try:
# Code that may raise an exception
result = 5 / 0 # This will raise a ZeroDivisionError
except ZeroDivisionError:
# Code to handle the exception
print("Error: can't divide by 0.")

In an actual application, the except code block would run a specific code to handle the error and ensure smooth further execution of the application without stopping it. 

You can also list multiple exceptions and provide different methods of handling each one. This way, you have complete control over how your program behaves in any given situation:

try:
# Code that may raise an exception
result = 5 / i # This will raise a NameError
except ZeroDivisionError:
# Code to handle the exception
print("Error: can't divide by 0.")
except NameError:
# Code to handle the exception
print("Error: variable was not declared.")

An alternative method of handling exceptions is simply to write a general exception handler that will catch any exception regardless of its type. This method, however, isn’t recommended, and it’s suggested to be as specific as possible with how individual exceptions are handled:

try:
# Code that may raise an exception
result = 5 / i # This will raise a NameError
except Exception as e:
# Code to handle the exception
print(f"An error occurred: {e}")

Lastly, you can use the else and finally code blocks together with the try-except structure. The else block is executed if no exceptions are raised, and the finally block will execute regardless of what happens. It’s just too cool to care.

try:
# Code that may raise an exception
result = 5 / 2
except ZeroDivisionError:
# Code to handle the exception
print("Error: can't divide by 0.")
else:
# Code to execute if no exception occurred
print(f"Result: {result}")
finally:
# Code that always executes
print("You can't contain me.")

These four code blocks are enough to handle any exceptions thrown your way. It ensures that the code has alternate paths to take no matter what happens and that your code won’t break when you least expect it.

Learning what they all mean is essential to handle each error correctly and know what to do. Check out the most common built-in exceptions listed below.

KeyError

Description: A KeyError exception is raised when you try to access a key not found in the dictionary. In simple terms, you’re attempting to use something from the dictionary (array) that doesn’t exist or hasn’t been defined yet.

Example:

# The dictionary only has 3 keys - a, b, and c
myDictionary = {'a':1, 'b':2, 'c':3}
# Attempt to print d which was not defined in the dictionary throws a KeyError exception
print(myDictionary['d'])

Solution: There can be many reasons a key is missing, so the most straightforward answer would be to add it to the dictionary manually. If the dictionary is created dynamically by reading data from a source, ensure the source has the required information. Finally, guarantee that the names match and that there aren’t any typos in the key name in the dictionary and the code that’s trying to use it.

ImportError

Description: The ImportError is raised when a module isn’t found, doesn’t exist, is corrupted or incomplete, or there’s a circular dependency between two or more modules.

Since Python 3.6, a more accurate and informative subclass of the ImportError exception was introduced – ModuleNotFoundError. It covers most cases when dealing with module imports but doesn’t cover circular dependencies.

Example:

# module_a.py
from module_b import b_function
def a_function():
b_function()
# module_b.py
from module_a import a_function
def b_function():
a_function()

The a_function() in module_a.py is trying to use the b_function() from module_b.py. The b_function() in module_b.py needs the a_function() from module_a.py. This is a classic dilemma of who came first – the chicken or the egg? Python definitely doesn’t have the answer to this philosophical question.

Solution: Reorganize your code to move shared functionality into a third module that both module_a.py and module_b.py can import without creating a circular dependency.

# shared_module.py
def shared_function():
print("Shared function")
# module_a.py
from shared_module import shared_function
def a_function():
shared_function()
a_function()
# module_b.py
from shared_module import shared_function
def b_function():
shared_function()
b_function()

ModuleNotFoundError

Description: This exception is a specific type of ImportError that comes up when you’re trying to import a non-existent module or when it’s defined incorrectly in your import statement. 

Example:

# Import the platforms module. It's not a built-in Python module, or exists as a file
import platforms
# Attempt to use the module and one of its functions throws a ModuleNotFoundError
userSystem = platforms.system()
print(userSystem)

Solution: Make sure that the module exists. See if it’s in the official Python built-in module index, or check your file directory to ensure the file is there (all modules must end with a .py extension). Alternatively, see if you’ve made a typo in the module name. It’s important to remember that the names are case-sensitive, so check that the capitalization is correct.

SyntaxError

Description: The SyntaxError exception occurs when there’s a mistake in how the code is written, and the interpreter can’t parse and execute it. The most common causes include missing or mismatched parentheses, brackets, colons, and incorrect indentation. 

Example:

print("Hello, World!" # Missing parentheses

Solution: Go back to review the code and fix any syntax issues. The exception provides a traceback that points to the location in the code where the error was made, making it easy to find. Remember that the interpreter might not always be 100% accurate, and the error might be located a line above or below where it’s indicated.

NameError

Description: This exception is raised when the interpreter can’t find a variable, function, or module with the given name. Simply put, it’s unsure what you’re referencing in the current scope, meaning that you didn’t define something earlier before using it.

Example:

# Attempt to print a variable
print(variable)
# The variable in question, declared only after the print function
variable = 5

Solution: Check for typos, declare variables before use, and ensure that functions or classes are defined before they are called.

TypeError

Description: An exception occurs when an operation or function is applied to an object of an inappropriate type. These are primarily logical errors, such as trying to add a numeric value with a string value or trying to find the length of a number. 

Example:

# Trying to add a string value with a numeric value
result = "10" + 5
print(result)

Solution: Check if all operations and functions are interacting only with objects that are compatible with them in type. You may also convert objects using functions such as int() or str() that will change the object type to a number or string, respectively.

IndexError

Description: The IndexError exception occurs when you try to access an index outside a given range. For example, an array might contain five items, but you’re attempting to access the 7th item, which doesn’t exist. 

Example:

# Array of items
my_list = [1, 2, 3]
# Attempt to print the 5th item
print(my_list[5])

Solution: To handle the IndexError exception class, avoid accessing indexes not in a given range. A standard solution is to check the bounds of a sequence first with functions such as len(). It’s important not to forget that in Python, most sequences will start at 0 and not 1, meaning that the first item will have an index of 0, and the last will be one number lower than the length of the entire sequence.

AttributeError

Description: In Python, attributes are values associated with an object. They are characteristics or properties that can be accessed using dot notation (object.attribute) and provide information about the object or its current state. 

An AttributeError may occur when trying to access or modify an attribute of an object that doesn’t exist or isn’t accessible. In other words, the specified attribute doesn’t fit and can’t be applied to the given object.

Example:

# The object is defined as an integer 5, which doesn't have an attribute "length"
my_object = 5
print(my_object.length)

Solution: To handle AttributeError issues, ensure that attributes accessed or modified are valid for the given object. It’s good to check the documentation of an object you’re using or use the hasattr() function to check if an attribute exists. For example:

my_object = 5
# Check if the object has an attribute called "length"
if hasattr(my_object, 'length'):
# Do something if it has it
else:
# Do something if it doesn't

FileNotFoundError

Description: The FileNotFound error message typically occurs in file I/O operations when trying to open, read, or write files. The exception instance is raised when attempting to access a file or directory unsuccessfully because it’s either not found or inaccessible.

Example:

# Attempt to open tells that such file that doesn't exist
with open('non_existent_file.txt', 'r') as file:
content = file.read()

Solution: Ensure that such a file exists in the directory. A common mistake is writing the wrong path to the directory from the script file or a typo somewhere in the path or file name. The file has to also be in a readable format that your application can understand. By default, Python can read or open many variations of text, database, CSV, JSON, and XML files, expanded by the libraries that may allow even more possibilities. Double-check if you’ve got the right tools.

ZeroDivisionError

Description: The ZeroDivisionError exception simply signifies an attempt to divide by zero. This operation is undefined in mathematics and doesn’t provide any sensible results; therefore, it doesn’t make sense in code either.

Example:

result = 10 / 0
print(result)

Solution: Double-check your code for zero denominators before performing any division operations. 

ValueError

Description: The ValueError exception is raised when a function receives an argument of the correct type but with an invalid value. This usually happens when the input isn’t within an expected range or doesn’t satisfy certain conditions.

Example:

# Attempt to convert a float value (10.5) to a decimal value (base 10)
x = int("10.5")
print(x)

Solution: The best way to handle this error is to validate input values before they’re used in operations or functions. You can use conditional statements or try-except blocks to catch and handle the ValueError exceptions cleanly and consistently.

Best practices for error handling

While many errors require different handling methods, you may notice some similarities. Here are some of the most common things to keep in mind:

  • Check for typos. The most common errors are human errors, so before turning to any complex solutions, take a step back and review your code. A scary error message might indicate a missing semicolon or a mistyped word. Most Python exceptions will provide a traceback, pointing to exactly where the error was made. 
  • Validate your data. Before plugging your data into a Python script, ensure it’s correct and makes sense. Many issues come from data that’s poorly formatted or doesn’t meet the requirements of a function. Use conditional statements to check if the information provided is within bounds and fits the action you’re trying to do with it.  
  • Use the try-except blocks. This is the big one. As Python provides a graceful and easy way of handling exceptions, you should take full advantage of it. If there’s a risk that your code might fail at any given line, wrap it into a try block and provide except to handle any exceptions you might expect. Expand it with else and finally blocks to provide your code more than one way out of an issue. 

Final words

This article covered the general knowledge of what errors and exceptions you can get in Python and a list of the most common ones so you know exactly how to deal with them. Writing clean and concise code can be an art form, so don’t worry about running into issues – they’re there to help you and guide you through. Knowing Python's different exceptions and errors allows you to take complete control of any situation and succeed in any coding project.

About the author

Zilvinas Tamulis

Technical Copywriter

Zilvinas is an experienced technical copywriter specializing in web development and network technologies. With extensive proxy and web scraping knowledge, he’s eager to share valuable insights and practical tips for confidently navigating the digital world.

LinkedIn

All information on Smartproxy Blog is provided on an "as is" basis and for informational purposes only. We make no representation and disclaim all liability with respect to your use of any information contained on Smartproxy Blog or any third-party websites that may be linked therein.

Frequently asked questions

What is a syntax error in Python?

A syntax error in Python is a type of error that occurs when the code violates the rules and structure of the Python programming language. It typically occurs because of incorrect use of keywords, missing or misplaced punctuation, or improper indentation. Python's interpreter cannot execute code with syntax errors, which will raise an error message with the location and reason for the syntax mistake.

What is a key error in Python?

© 2018-2024 smartproxy.com, All Rights Reserved