Assertions in Python are statements that assert or assume a condition to be true. If the condition turns out to be false, Python raises an AssertionError exception. They are used to detect programming errors that should never occur if the code is correct.
The easiest way to think of an assertion is to liken it to a raise-if statement (or to be more accurate, a raise-if-not statement). An expression is tested, and if the result comes up false, an exception is raised.
Assertions are carried out by the assert statement, the newest keyword to Python, introduced in version 1.5.
Programmers often place assertions at the start of a function to check for valid input, and after a function call to check for valid output.
The assert Statement
In Python, assertions use the assert keyword followed by an expression. If the expression evaluates to False, an AssertionError is raised. Following is the syntax of assertion −
assert condition, message
Where,
condition − A boolean expression that should be true.
message (optional) − An optional message to be displayed if the assertion fails.
Learn Python in-depth with real-world projects through our Python certification course. Enroll and become a certified expert to boost your career.
Using Assertions
Assertions are generally used during development and testing phases to check conditions that should always hold true.
Example
In the following example, we are using assertions to ensure that the variable “num” falls within the valid range of “0” to “100”. If the assertion fails, Python raises an “AssertionError”, preventing further execution of the subsequent print statement −
print('Enter marks out of 100:')
num =75assert num >=0and num <=100print('Marks obtained:', num)
num =125assert num >=0and num <=100print('Marks obtained:', num)# This line won't be reached if assertion fails
Following is the output of the above code −
Enter marks out of 100:
Marks obtained: 75
Traceback (most recent call last):
File "/home/cg/root/66723bd115007/main.py", line 7, in <module>
assert num >= 0 and num <= 100
AssertionError
Custom Error Messages
To display a custom error message when an assertion fails, include a string after the expression in the assert statement −
assert num >=0and num <=100,"Only numbers in the range 0-100 are accepted"
Handling AssertionError
Assertions can be caught and handled like any other exception using a try-except block. If they are not handled, they will terminate the program and produce a traceback −
try:
num =int(input('Enter a number: '))assert num >=0,"Only non-negative numbers are accepted"print(num)except AssertionError as msg:print(msg)
It will produce the following output −
Enter a number: -87
Only non-negative numbers are accepted
Assertions vs. Exceptions
Assertions are used to check internal state and invariants that should always be true. Whereas, exceptions helps in handling runtime errors and exceptional conditions that may occur during normal execution.
Assertions are disabled by default in Python’s optimized mode (-O or python -O script.py). Therefore, they should not be used to enforce constraints that are required for the correct functioning of the program in production environments.
Logging is the process of recording messages during the execution of a program to provide runtime information that can be useful for monitoring, debugging, and auditing.
In Python, logging is achieved through the built-in logging module, which provides a flexible framework for generating log messages.
Benefits of Logging
Following are the benefits of using logging in Python −
Debugging − Helps identify and diagnose issues by capturing relevant information during program execution.
Monitoring − Provides insights into the application’s behavior and performance.
Auditing − Keeps a record of important events and actions for security purposes.
Troubleshooting − Facilitates tracking of program flow and variable values to understand unexpected behavior.
Learn Python in-depth with real-world projects through our Python certification course. Enroll and become a certified expert to boost your career.
Components of Python Logging
Python logging consists of several key components that work together to manage and output log messages effectively −
Logger − It is the main entry point that you use to emit log messages. Each logger instance is named and can be configured independently.
Handler − It determines where log messages are sent. Handlers send log messages to different destinations such as the console, files, sockets, etc.
Formatter − It specifies the layout of log messages. Formatters define the structure of log records by specifying which information to include (e.g., timestamp, log level, message).
Logger Level − It defines the severity level of log messages. Messages below this level are ignored. Common levels include DEBUG, INFO, WARNING, ERROR, and CRITICAL.
Filter − It is the optional components that provide finer control over which log records are processed and emitted by a handler.
Logging Levels
Logging levels in Python define the severity of log messages, allowing developers to categorize and filter messages based on their importance. Each logging level has a specific purpose and helps in understanding the significance of the logged information −
DEBUG − Detailed information, typically useful only for debugging purposes. These messages are used to trace the flow of the program and are usually not seen in production environments.
INFO − Confirmation that things are working as expected. These messages provide general information about the progress of the application.
WARNING − Indicates potential issues that do not prevent the program from running but might require attention. These messages can be used to alert developers about unexpected situations.
ERROR − Indicates a more serious problem that prevents a specific function or operation from completing successfully. These messages highlight errors that need immediate attention but do not necessarily terminate the application.
CRITICAL − The most severe level, indicating a critical error that may lead to the termination of the program. These messages are reserved for critical failures that require immediate intervention.
Usage
Following are the usage scenarios for each logging level in Python applications −
Choosing the Right Level − Selecting the appropriate logging level ensures that log messages provide relevant information without cluttering the logs.
Setting Levels − Loggers, handlers, and specific log messages can be configured with different levels to control which messages are recorded and where they are outputted.
Hierarchy − Logging levels are hierarchical, meaning that setting a level on a logger also affects the handlers and log messages associated with it.
Basic Logging Example
Following is a basic logging example in Python to demonstrate its usage and functionality −
Open Compiler
import logging
# Configure logging
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(levelname)s - %(message)s')# Example usagedefcalculate_sum(a, b):
logging.debug(f"Calculating sum of {a} and {b}")
result = a + b
logging.info(f"Sum calculated successfully: {result}")return result
# Main programif __name__ =="__main__":
logging.info("Starting the program")
result = calculate_sum(10,20)
logging.info("Program completed")
Output
Following is the output of the above code −
2024-06-19 09:00:06,774 - INFO - Starting the program
2024-06-19 09:00:06,774 - DEBUG - Calculating sum of 10 and 20
2024-06-19 09:00:06,774 - INFO - Sum calculated successfully: 30
2024-06-19 09:00:06,775 - INFO - Program completed
Configuring Logging
Configuring logging in Python refers to setting up various components such as loggers, handlers, and formatters to control how and where log messages are stored and displayed. This configuration allows developers to customize logging behavior according to their application’s requirements and deployment environment.
Example
In the following example, the getLogger() function retrieves or creates a named logger. Loggers are organized hierarchically based on their names. Then, handlers like “StreamHandler” (console handler) are created to define where log messages go. They can be configured with specific log levels and formatters.
The formatters specify the layout of log records, determining how log messages appear when printed or stored −
Open Compiler
import logging
# Create logger
logger = logging.getLogger('my_app')
logger.setLevel(logging.DEBUG)# Set global log level# Create console handler and set level to debug
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)# Create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)# Add console handler to logger
logger.addHandler(console_handler)# Example usage
logger.debug('This is a debug message')
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')
logger.critical('This is a critical message')
The result produced is as shown below −
2024-06-19 09:05:20,852 - my_app - DEBUG - This is a debug message
2024-06-19 09:05:20,852 - my_app - INFO - This is an info message
2024-06-19 09:05:20,852 - my_app - WARNING - This is a warning message
2024-06-19 09:05:20,852 - my_app - ERROR - This is an error message
2024-06-19 09:05:20,852 - my_app - CRITICAL - This is a critical message
Logging Handlers
Logging handlers in Python determine where and how log messages are processed and outputted. They play an important role in directing log messages to specific destinations such as the console, files, email, databases, or even remote servers.
Each handler can be configured independently to control the format, log level, and other properties of the messages it processes.
Types of Logging Handlers
Following are the various types of logging handlers in Python −
StreamHandler − Sends log messages to streams such as sys.stdout or sys.stderr. Useful for displaying log messages in the console or command line interface.
FileHandler − Writes log messages to a specified file on the file system. Useful for persistent logging and archiving of log data.
RotatingFileHandler − Similar to FileHandler but automatically rotates log files based on size or time intervals. Helps manage log file sizes and prevent them from growing too large.
SMTPHandler − Sends log messages as emails to designated recipients via SMTP. Useful for alerting administrators or developers about critical issues.
SysLogHandler − Sends log messages to the system log on Unix-like systems (e.g., syslog). Allows integration with system-wide logging facilities.
MemoryHandler − Buffers log messages in memory and sends them to a target handler after reaching a certain buffer size or timeout. Useful for batching and managing bursts of log messages.
HTTPHandler − Sends log messages to a web server via HTTP or HTTPS. Enables logging messages to a remote server or logging service.
User-defined exceptions in Python are custom error classes that you create to handle specific error conditions in your code. They are derived from the built-in Exception class or any of its sub classes.
User-defined exceptions provide more precise control over error handling in your application −
Clarity − They provide specific error messages that make it clear what went wrong.
Granularity − They allow you to handle different error conditions separately.
Maintainability − They centralize error handling logic, making your code easier to maintain.
How to Create a User-Defined Exception
To create a user-defined exception, follow these steps −
Step 1 − Define the Exception Class
Create a new class that inherits from the built-in “Exception” class or any other appropriate base class. This new class will serve as your custom exception.
classMyCustomError(Exception):pass
Explanation
Inheritance − By inheriting from “Exception”, your custom exception will have the same behaviour and attributes as the built-in exceptions.
Class Definition − The class is defined using the standard Python class syntax. For simple custom exceptions, you can define an empty class body using the “pass” statement.
Step 2 − Initialize the Exception
Implement the “__init__” method to initialize any attributes or provide custom error messages. This allows you to pass specific information about the error when raising the exception.
classInvalidAgeError(Exception):def__init__(self, age, message="Age must be between 18 and 100"):
self.age = age
self.message = message
super().__init__(self.message)</code></pre>
Explanation
Attributes − Define attributes such as "age" and "message" to store information about the error.
Initialization − The "__init__" method initializes these attributes. The "super().__init__(self.message)" call ensures that the base "Exception" class is properly initialized with the error message.
Default Message − A default message is provided, but you can override it when raising the exception.
Step 3 − Optionally Override "__str__" or "__repr__"
Override the "__str__" or "__repr__" method to provide a custom string representation of the exception. This is useful for printing or logging the exception.
classInvalidAgeError(Exception):def__init__(self, age, message="Age must be between 18 and 100"):
self.age = age
self.message = message
super().__init__(self.message)def__str__(self):returnf"{self.message}. Provided age: {self.age}"</code></pre>
Explanation
__str__ Method − The "__str__" method returns a string representation of the exception. This is what will be displayed when the exception is printed.
Custom Message − Customize the message to include relevant information, such as the provided age in this example.
Learn Python in-depth with real-world projects through our Python certification course. Enroll and become a certified expert to boost your career.
Raising User-Defined Exceptions
Once you have defined a custom exception, you can raise it in your code to signify specific error conditions. Raising user-defined exceptions involves using the raise statement, which can be done with or without custom messages and attributes.
Syntax
Following is the basic syntax for raising an exception −
raise ExceptionType(args)
Example
In this example, the "set_age" function raises an "InvalidAgeError" if the age is outside the valid range −
defset_age(age):if age <18or age >100:raise InvalidAgeError(age)print(f"Age is set to {age}")
Handling User-Defined Exceptions
Handling user-defined exceptions in Python refers to using "try-except" blocks to catch and respond to the specific conditions that your custom exceptions represent. This allows your program to handle errors gracefully and continue running or to take specific actions based on the type of exception raised.
Syntax
Following is the basic syntax for handling exceptions −
try:# Code that may raise an exceptionexcept ExceptionType as e:# Code to handle the exception
Example
In the below example, the "try" block calls "set_age" with an invalid age. The "except" block catches the "InvalidAgeError" and prints the custom error message −
try:
set_age(150)except InvalidAgeError as e:print(f"Invalid age: {e.age}. {e.message}")
Complete Example
Combining all the steps, here is a complete example of creating and using a user-defined exception −
Open Compiler
classInvalidAgeError(Exception):def__init__(self, age, message="Age must be between 18 and 100"):
self.age = age
self.message = message
super().__init__(self.message)def__str__(self):returnf"{self.message}. Provided age: {self.age}"defset_age(age):if age <18or age >100:raise InvalidAgeError(age)print(f"Age is set to {age}")try:
set_age(150)except InvalidAgeError as e:print(f"Invalid age: {e.age}. {e.message}")
In a Python program, if there is another try-except construct either inside either a try block or inside its except block, it is known as a nested-try block. This is needed when different blocks like outer and inner may cause different errors. To handle them, we need nested try blocks.
We start with an example having a single “try − except − finally” construct. If the statements inside try encounter exception, it is handled by except block. With or without exception occurred, the finally block is always executed.
Example 1
Here, the try block has “division by 0” situation, hence the except block comes into play. It is equipped to handle the generic exception with Exception class.
Let us now see how to nest the try constructs. We put another “try − except − finally” blocks inside the existing try block. The except keyword for inner try now handles generic Exception, while we ask the except block of outer try to handle ZeroDivisionError.
Since exception doesn’t occur in the inner try block, its corresponding generic Except isn’t called. The division by 0 situation is handled by outer except clause.
Open Compiler
a=10
b=0try:print(a/b)try:print("This is inner try block")except Exception:print("General exception")finally:print("inside inner finally block")except ZeroDivisionError:print("Division by 0")finally:print("inside outer finally block")
It will produce the following output −
Division by 0
inside outer finally block
Example 3
Now we reverse the situation. Out of the nested try blocks, the outer one doesn’t have any exception raised, but the statement causing division by 0 is inside inner try, and hence the exception handled by inner except block. Obviously, the except part corresponding to outer try: will not be called upon.
Open Compiler
a=10
b=0try:print("This is outer try block")try:print(a/b)except ZeroDivisionError:print("Division by 0")finally:print("inside inner finally block")except Exception:print("General Exception")finally:print("inside outer finally block")
It will produce the following output −
This is outer try block
Division by 0
inside inner finally block
inside outer finally block
In the end, let us discuss another situation which may occur in case of nested blocks. While there isn’t any exception in the outer try:, there isn’t a suitable except block to handle the one inside the inner try: block.
Example 4
In the following example, the inner try: faces “division by 0”, but its corresponding except: is looking for KeyError instead of ZeroDivisionError. Hence, the exception object is passed on to the except: block of the subsequent except statement matching with outer try: statement. There, the zeroDivisionError exception is trapped and handled.
Open Compiler
a=10
b=0try:print("This is outer try block")try:print(a/b)except KeyError:print("Key Error")finally:print("inside inner finally block")except ZeroDivisionError:print("Division by 0")finally:print("inside outer finally block")
It will produce the following output −
This is outer try block
inside inner finally block
Division by 0
inside outer finally block
Exception chaining is a technique of handling exceptions by re-throwing a caught exception after wrapping it inside a new exception. The original exception is saved as a property (such as cause) of the new exception.
During the handling of one exception ‘A’, it is possible that another exception ‘B’ may occur. It is useful to know about both exceptions in order to debug the problem. Sometimes it is useful for an exception handler to deliberately re-raise an exception, either to provide extra information or to translate an exception to another type.
In Python 3.x, it is possible to implement exception chaining. If there is any unhandled exception inside an except section, it will have the exception being handled attached to it and included in the error message.
Example
In the following code snippet, trying to open a non-existent file raises FileNotFoundError. It is detected by the except block. While handling another exception is raised.
Open Compiler
try:open("nofile.txt")except OSError:raise RuntimeError("unable to handle error")
It will produce the following output −
Traceback (most recent call last):
File "/home/cg/root/64afcad39c651/main.py", line 2, in <module>
open("nofile.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'nofile.txt'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/cg/root/64afcad39c651/main.py", line 4, in <module>
raise RuntimeError("unable to handle error")
RuntimeError: unable to handle error
The raise . . from Statement
If you use an optional from clause in the raise statement, it indicates that an exception is a direct consequence of another. This can be useful when you are transforming exceptions. The token after from keyword should be the exception object.
Open Compiler
try:open("nofile.txt")except OSError as exc:raise RuntimeError from exc
It will produce the following output −
Traceback (most recent call last):
File "/home/cg/root/64afcad39c651/main.py", line 2, in <module>
open("nofile.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'nofile.txt'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/cg/root/64afcad39c651/main.py", line 4, in <module>
raise RuntimeError from exc
RuntimeError
Learn Python in-depth with real-world projects through our Python certification course. Enroll and become a certified expert to boost your career.
The raise . . from None Statement
If we use None in from clause instead of exception object, the automatic exception chaining that was found in the earlier example is disabled.
Open Compiler
try:open("nofile.txt")except OSError as exc:raise RuntimeError fromNone
It will produce the following output −
Traceback (most recent call last):
File "C:\Python311\hello.py", line 4, in <module>
raise RuntimeError from None
RuntimeError
The __context__ and __cause__ Expression
Raising an exception in the except block will automatically add the captured exception to the __context__ attribute of the new exception. Similarly, you can also add __cause__ to any exception using the expression raise … from syntax.
Open Compiler
try:try:raise ValueError("ValueError")except ValueError as e1:raise TypeError("TypeError")from e1
except TypeError as e2:print("The exception was",repr(e2))print("Its __context__ was",repr(e2.__context__))print("Its __cause__ was",repr(e2.__cause__))
It will produce the following output −
The exception was TypeError('TypeError')
Its __context__ was ValueError('ValueError')
Its __cause__ was ValueError('ValueError')
In Python, you can raise exceptions explicitly using the raise statement. Raising exceptions allows you to indicate that an error has occurred and to control the flow of your program by handling these exceptions appropriately.
Raising an exception refers to explicitly trigger an error condition in your program. This can be useful for handling situations where the normal flow of your program cannot continue due to an error or an unexpected condition.
In Python, you can raise built-in exceptions like ValueError or TypeError to indicate common error conditions. Additionally, you can create and raise custom exceptions.
Raising Built-in Exceptions
You can raise any built-in exception by creating an instance of the exception class and using the raise statement. Following is the syntax −
raise Exception("This is a general exception")
Example
Here is an example where we raise a ValueError when a function receives an invalid argument −
Open Compiler
defdivide(a, b):if b ==0:raise ValueError("Cannot divide by zero")return a / b
try:
result = divide(10,0)except ValueError as e:print(e)
Following is the output of the above code −
Cannot divide by zero
Learn Python in-depth with real-world projects through our Python certification course. Enroll and become a certified expert to boost your career.
Raising Custom Exceptions
In addition to built-in exceptions, you can define and raise your own custom exceptions by creating a new exception class that inherits from the base Exception class or any of its subclasses −
Open Compiler
classMyCustomError(Exception):passdefrisky_function():raise MyCustomError("Something went wrong in risky_function")try:
risky_function()except MyCustomError as e:print(e)
Output of the above code is as shown below −
Something went wrong in risky_function
Creating Custom Exceptions
Custom exceptions is useful for handling specific error conditions that are unique to your application, providing more precise error reporting and control.
To create a custom exception in Python, you define a new class that inherits from the built-in Exception class or any other appropriate built-in exception class. This custom exception class can have additional attributes and methods to provide more detailed context about the error condition.
Example
In this example −
We define a custom exception class “InvalidAgeError” that inherits from “Exception”.
The __init__() method initializes the exception with the invalid age and a default error message.
The set_age() function raises “InvalidAgeError” if the provided age is outside the valid range.
Open Compiler
classInvalidAgeError(Exception):def__init__(self, age, message="Age must be between 18 and 100"):
self.age = age
self.message = message
super().__init__(self.message)defset_age(age):if age <18or age >100:raise InvalidAgeError(age)print(f"Age is set to {age}")try:
set_age(150)except InvalidAgeError as e:print(f"Invalid age: {e.age}. {e.message}")
The result obtained is as shown below −
Invalid age: 150. Age must be between 18 and 100
Re-Raising Exceptions
Sometimes, you may need to catch an exception, perform specific actions (such as logging, cleanup, or providing additional context), and then re-raise the same exception to be handled further up the call stack
This is useful when you want to ensure certain actions are taken when an exception occurs, but still allow the exception to propagate for higher-level handling.
To re-raise an exception in Python, you use the “raise” statement without specifying an exception, which will re-raise the last exception that was active in the current scope.
Example
In the following example −
The process_file() function attempts to open and read a file.
If the file is not found, it prints an error message and re-raises the “FileNotFoundError” exception.
The exception is then caught and handled at a higher level in the call stack.
In Python, the try-finally block is used to ensure that certain code executes, regardless of whether an exception is raised or not. Unlike the try-except block, which handles exceptions, the try-finally block focuses on cleanup operations that must occur, ensuring resources are properly released and critical tasks are completed.
Syntax
The syntax of the try-finally statement is as follows −
try:# Code that might raise exceptions
risky_code()finally:# Code that always runs, regardless of exceptions
cleanup_code()
In Python, when using exception handling with try blocks, you have the option to include either except clauses to catch specific exceptions or a finally clause to ensure certain cleanup operations are executed, but not both together.
Example
Let us consider an example where we want to open a file in write mode (“w”), writes some content to it, and ensures the file is closed regardless of success or failure using a finally block −
try:
fh =open("testfile","w")
fh.write("This is my test file for exception handling!!")finally:print("Error: can\'t find file or read data")
fh.close()
If you do not have permission to open the file in writing mode, then it will produce the following output −
Error: can't find file or read data
The same example can be written more cleanly as follows −
Open Compiler
try:
fh =open("testfile","w")try:
fh.write("This is my test file for exception handling!!")finally:print("Going to close the file")
fh.close()except IOError:print("Error: can\'t find file or read data")</code></pre>
When an exception is thrown in the try block, the execution immediately passes to the finally block. After all the statements in the finally block are executed, the exception is raised again and is handled in the except statements if present in the next higher layer of the try-except statement.
Exception with Arguments
An exception can have an argument, which is a value that gives additional information about the problem. The contents of the argument vary by exception. You capture an exception's argument by supplying a variable in the except clause as follows −
try:
You do your operations here
......................except ExceptionType as Argument:
You can print value of Argument here...
If you write the code to handle a single exception, you can have a variable follow the name of the exception in the except statement. If you are trapping multiple exceptions, you can have a variable follow the tuple of the exception.
This variable receives the value of the exception mostly containing the cause of the exception. The variable can receive a single value or multiple values in the form of a tuple. This tuple usually contains the error string, the error number, and an error location.
Example
Following is an example for a single exception −
Open Compiler
# Define a function here.deftemp_convert(var):try:returnint(var)except ValueError as Argument:print("The argument does not contain numbers\n",Argument)# Call above function here.
temp_convert("xyz")
It will produce the following output −
The argument does not contain numbers
invalid literal for int() with base 10: 'xyz'
In Python, the try-except block is used to handle exceptions and errors gracefully, ensuring that your program can continue running even when something goes wrong. This tutorial will cover the basics of using the try-except block, its syntax, and best practices.
Exception handling allows you to manage errors in your code by capturing exceptions and taking appropriate actions instead of letting the program crash. An exception is an error that occurs during the execution of a program, and handling these exceptions ensures your program can respond to unexpected situations.
The try-except block in Python is used to catch and handle exceptions. The code that might cause an exception is placed inside the try block, and the code to handle the exception is placed inside the except block.
Syntax
Following is the basic syntax of the try-except block in Python −
try:# Code that might cause an exception
risky_code()except SomeException as e:# Code that runs if an exception occurs
handle_exception(e)
Example
In this example, if you enter a non-numeric value, a ValueError will be raised. If you enter zero, a ZeroDivisionError will be raised. The except blocks handle these exceptions and prints appropriate error messages −
try:
number =int(input("Enter a number: "))
result =10/ number
print(f"Result: {result}")except ZeroDivisionError as e:print("Error: Cannot divide by zero.")except ValueError as e:print("Error: Invalid input. Please enter a valid number.")
Handling Multiple Exceptions
In Python, you can handle multiple types of exceptions using multiple except blocks within a single try-except statement. This allows your code to respond differently to different types of errors that may occur during execution.
Syntax
Following is the basic syntax for handling multiple exceptions in Python −
try:# Code that might raise exceptions
risky_code()except FirstExceptionType:# Handle the first type of exception
handle_first_exception()except SecondExceptionType:# Handle the second type of exception
handle_second_exception()# Add more except blocks as needed for other exception types
Example
In the following example −
If you enter zero as the divisor, a “ZeroDivisionError” will be raised, and the corresponding except ZeroDivisionError block will handle it by printing an error message.
If you enter a non-numeric input for either the dividend or the divisor, a “ValueError” will be raised, and the except ValueError block will handle it by printing a different error message.
try:
dividend =int(input("Enter the dividend: "))
divisor =int(input("Enter the divisor: "))
result = dividend / divisor
print(f"Result of division: {result}")except ZeroDivisionError:print("Error: Cannot divide by zero.")except ValueError:print("Error: Invalid input. Please enter valid integers.")
Learn Python in-depth with real-world projects through our Python certification course. Enroll and become a certified expert to boost your career.
Using Else Clause with Try-Except Block
In Python, the else clause can be used in conjunction with the try-except block to specify code that should run only if no exceptions occur in the try block. This provides a way to differentiate between the main code that may raise exceptions and additional code that should only execute under normal conditions.
Syntax
Following is the basic syntax of the else clause in Python −
try:# Code that might raise exceptions
risky_code()except SomeExceptionType:# Handle the exception
handle_exception()else:# Code that runs if no exceptions occurred
no_exceptions_code()
Example
In the following example −
If you enter a non-integer input, a ValueError will be raised, and the corresponding except ValueError block will handle it.
If you enter zero as the denominator, a ZeroDivisionError will be raised, and the corresponding except ZeroDivisionError block will handle it.
If the division is successful (i.e., no exceptions are raised), the else block will execute and print the result of the division.
try:
numerator =int(input("Enter the numerator: "))
denominator =int(input("Enter the denominator: "))
result = numerator / denominator
except ValueError:print("Error: Invalid input. Please enter valid integers.")except ZeroDivisionError:print("Error: Cannot divide by zero.")else:print(f"Result of division: {result}")
The Finally Clause
The finally clause provides a mechanism to guarantee that specific code will be executed, regardless of whether an exception is raised or not. This is useful for performing cleanup actions such as closing files or network connections, releasing locks, or freeing up resources.
Syntax
Following is the basic syntax of the finally clause in Python −
try:# Code that might raise exceptions
risky_code()except SomeExceptionType:# Handle the exception
handle_exception()else:# Code that runs if no exceptions occurred
no_exceptions_code()finally:# Code that always runs, regardless of exceptions
cleanup_code()
Example
In this example −
If the file “example.txt” exists, its content is read and printed, and the else block confirms the successful operation.
If the file is not found (FileNotFoundError), an appropriate error message is printed in the except block.
The finally block ensures that the file is closed (file.close()) regardless of whether the file operation succeeds or an exception occurs.
try:file=open("example.txt","r")
content =file.read()print(content)except FileNotFoundError:print("Error: The file was not found.")else:print("File read operation successful.")finally:if'file'inlocals():file.close()print("File operation is complete.")
Exception Handling in Python
Exception handling in Python refers to managing runtime errors that may occur during the execution of a program. In Python, exceptions are raised when errors or unexpected situations arise during program execution, such as division by zero, trying to access a file that does not exist, or attempting to perform an operation on incompatible data types.
Python provides two very important features to handle any unexpected error in your Python programs and to add debugging capabilities in them −
Exception Handling − This would be covered in this tutorial. Here is a list of standard Exceptions available in Python: Standard Exceptions.
An assertion is a sanity-check that you can turn on or turn off when you are done with your testing of the program.
The easiest way to think of an assertion is to liken it to a raise-if statement (or to be more accurate, a raise-if-not statement). An expression is tested, and if the result comes up false, an exception is raised.
Assertions are carried out by the assert statement, the newest keyword to Python, introduced in version 1.5.
Programmers often place assertions at the start of a function to check for valid input, and after a function call to check for valid output.
The assert Statement
When it encounters an assert statement, Python evaluates the accompanying expression, which is hopefully true. If the expression is false, Python raises an AssertionError exception.
The syntax for assert is −
assert Expression[, Arguments]
If the assertion fails, Python uses ArgumentExpression as the argument for the AssertionError. AssertionError exceptions can be caught and handled like any other exception using the try-except statement, but if not handled, they will terminate the program and produce a trace back.
Example
Here is a function that converts a temperature from degrees Kelvin to degrees Fahrenheit. Since zero degrees Kelvin is as cold as it gets, the function bails out if it sees a negative temperature −
Open Compiler
defKelvinToFahrenheit(Temperature):assert(Temperature >=0),"Colder than absolute zero!"return((Temperature-273)*1.8)+32print(KelvinToFahrenheit(273))print(int(KelvinToFahrenheit(505.78)))print(KelvinToFahrenheit(-5))
When the above code is executed, it produces the following result −
32.0
451
Traceback (most recent call last):
File "test.py", line 9, in <module>
print (KelvinToFahrenheit(-5))
File "test.py", line 4, in KelvinToFahrenheit
assert (Temperature >= 0),"Colder than absolute zero!"
AssertionError: Colder than absolute zero!
Learn Python in-depth with real-world projects through our Python certification course. Enroll and become a certified expert to boost your career.
What is Exception?
An exception is an event, which occurs during the execution of a program that disrupts the normal flow of the program’s instructions. In general, when a Python script encounters a situation that it cannot cope with, it raises an exception. An exception is a Python object that represents an error.
When a Python script raises an exception, it must either handle the exception immediately otherwise it terminates and quits.
Handling an Exception in Python
If you have some suspicious code that may raise an exception, you can defend your program by placing the suspicious code in a try: block. After the try: block, include an except: statement, followed by a block of code which handles the problem as elegantly as possible.
The try: block contains statements which are susceptible for exception
If exception occurs, the program jumps to the except: block.
If no exception in the try: block, the except: block is skipped.
Syntax
Here is the simple syntax of try…except…else blocks −
try:
You do your operations here
......................except ExceptionI:
If there is ExceptionI, then execute this block.except ExceptionII:
If there is ExceptionII, then execute this block.......................else:
If there is no exception then execute this block.
Here are few important points about the above-mentioned syntax −
A single try statement can have multiple except statements. This is useful when the try block contains statements that may throw different types of exceptions.
You can also provide a generic except clause, which handles any exception.
After the except clause(s), you can include an else clause. The code in the else block executes if the code in the try: block does not raise an exception.
The else block is a good place for code that does not need the try: block’s protection.
Example
This example opens a file, writes content in the file and comes out gracefully because there is no problem at all.
Open Compiler
try:
fh =open("testfile","w")
fh.write("This is my test file for exception handling!!")except IOError:print("Error: can\'t find file or read data")else:print("Written content in the file successfully")
fh.close()
It will produce the following output −
Written content in the file successfully
However, change the mode parameter in open() function to “w”. If the testfile is not already present, the program encounters IOError in except block, and prints following error message −
Error: can't find file or read data
Example
This example tries to open a file where you do not have write permission, so it raises an exception −
Open Compiler
try:
fh =open("testfile","r")
fh.write("This is my test file for exception handling!!")except IOError:print("Error: can\'t find file or read data")else:print("Written content in the file successfully")
This produces the following result −
Error: can't find file or read data
The except Clause with No Exceptions
You can also use the except statement with no exceptions defined as follows −
try:
You do your operations here;......................except:
If there isany exception, then execute this block.......................else:
If there is no exception then execute this block.
This kind of a try-except statement catches all the exceptions that occur. Using this kind of try-except statement is not considered a good programming practice though, because it catches all exceptions but does not make the programmer identify the root cause of the problem that may occur.
The except Clause with Multiple Exceptions
You can also use the same except statement to handle multiple exceptions as follows −
try:
You do your operations here;......................except(Exception1[, Exception2[,...ExceptionN]]]):
If there isany exception from the given exception list,
then execute this block.......................else:
If there is no exception then execute this block.
The try-finally Clause
You can use a finally: block along with a try: block. The finally block is a place to put any code that must execute, whether the try-block raised an exception or not. The syntax of the try-finally statement is this −
try:
You do your operations here;......................
Due to any exception, this may be skipped.finally:
This would always be executed.......................
You cannot use else clause as well along with a finally clause.
Example
Open Compiler
try:
fh =open("testfile","w")
fh.write("This is my test file for exception handling!!")finally:print("Error: can\'t find file or read data")
If you do not have permission to open the file in writing mode, then this will produce the following result −
Error: can't find file or read data
Same example can be written more cleanly as follows −
Open Compiler
try:
fh =open("testfile","w")try:
fh.write("This is my test file for exception handling!!")finally:print("Going to close the file")
fh.close()except IOError:print("Error: can\'t find file or read data")</code></pre>
When an exception is thrown in the try block, the execution immediately passes to the finally block. After all the statements in the finally block are executed, the exception is raised again and is handled in the except statements if present in the next higher layer of the try-except statement.
Argument of an Exception
An exception can have an argument, which is a value that gives additional information about the problem. The contents of the argument vary by exception. You capture an exception's argument by supplying a variable in the except clause as follows −
try:
You do your operations here;......................except ExceptionType, Argument:
You can print value of Argument here...
If you write the code to handle a single exception, you can have a variable follow the name of the exception in the except statement. If you are trapping multiple exceptions, you can have a variable follow the tuple of the exception.
This variable receives the value of the exception mostly containing the cause of the exception. The variable can receive a single value or multiple values in the form of a tuple. This tuple usually contains the error string, the error number, and an error location.
Example
Following is an example for a single exception −
Open Compiler
# Define a function here.deftemp_convert(var):try:returnint(var)except ValueError as Argument:print("The argument does not contain numbers\n", Argument)# Call above function here.
temp_convert("xyz")
This produces the following result −
The argument does not contain numbers
invalid literal for int() with base 10: 'xyz'
Raising an Exceptions
You can raise exceptions in several ways by using the raise statement. The general syntax for the raise statement is as follows.
Syntax
raise [Exception [, args [, traceback]]]
Here, Exception is the type of exception (for example, NameError) and argument is a value for the exception argument. The argument is optional; if not supplied, the exception argument is None.
The final argument, trace back, is also optional (and rarely used in practice), and if present, is the traceback object used for the exception.
Example
An exception can be a string, a class or an object. Most of the exceptions that the Python core raises are classes, with an argument that is an instance of the class. Defining new exceptions is quite easy and can be done as follows −
# The code below to this would not be executed# if we raise the exception</code></pre>
Note: In order to catch an exception, an "except" clause must refer to the same exception thrown either class object or simple string. For example, to capture above exception, we must write the except clause as follows −
try:
Business Logic here...except"Invalid level!":
Exception handling here...else:
Rest of the code here...
User-Defined Exceptions
Python also allows you to create your own exceptions by deriving classes from the standard built-in exceptions.
Here is an example related to RuntimeError. Here, a class is created that is subclassed from RuntimeError. This is useful when you need to display more specific information when an exception is caught.
In the try block, the user-defined exception is raised and caught in the except block. The variable e is used to create an instance of the class Networkerror.
Here is a list of Standard Exceptions available in Python −
Sr.No.
Exception Name & Description
1
ExceptionBase class for all exceptions
2
StopIterationRaised when the next() method of an iterator does not point to any object.
3
SystemExitRaised by the sys.exit() function.
4
StandardErrorBase class for all built-in exceptions except StopIteration and SystemExit.
5
ArithmeticErrorBase class for all errors that occur for numeric calculation.
6
OverflowErrorRaised when a calculation exceeds maximum limit for a numeric type.
7
FloatingPointErrorRaised when a floating point calculation fails.
8
ZeroDivisionErrorRaised when division or modulo by zero takes place for all numeric types.
9
AssertionErrorRaised in case of failure of the Assert statement.
10
AttributeErrorRaised in case of failure of attribute reference or assignment.
11
EOFErrorRaised when there is no input from either the raw_input() or input() function and the end of file is reached.
12
ImportErrorRaised when an import statement fails.
13
KeyboardInterruptRaised when the user interrupts program execution, usually by pressing Ctrl+c.
14
LookupErrorBase class for all lookup errors.
15
IndexErrorRaised when an index is not found in a sequence.
16
KeyErrorRaised when the specified key is not found in the dictionary.
17
NameErrorRaised when an identifier is not found in the local or global namespace.
18
UnboundLocalErrorRaised when trying to access a local variable in a function or method but no value has been assigned to it.
19
EnvironmentErrorBase class for all exceptions that occur outside the Python environment.
20
IOErrorRaised when an input/ output operation fails, such as the print statement or the open() function when trying to open a file that does not exist.
21
IOErrorRaised for operating system-related errors.
22
SyntaxErrorRaised when there is an error in Python syntax.
23
IndentationErrorRaised when indentation is not specified properly.
24
SystemErrorRaised when the interpreter finds an internal problem, but when this error is encountered the Python interpreter does not exit.
25
SystemExitRaised when Python interpreter is quit by using the sys.exit() function. If not handled in the code, causes the interpreter to exit.
26
TypeErrorRaised when an operation or function is attempted that is invalid for the specified data type.
27
ValueErrorRaised when the built-in function for a data type has the valid type of arguments, but the arguments have invalid values specified.
28
RuntimeErrorRaised when a generated error does not fall into any category.
29
NotImplementedErrorRaised when an abstract method that needs to be implemented in an inherited class is not actually implemented.
In Python, syntax errors are among the most common errors encountered by programmers, especially those who are new to the language. This tutorial will help you understand what syntax errors are, how to identify them, and how to fix them.
What is a Syntax Error?
A syntax error in Python (or any programming language) is an error that occurs when the code does not follow the syntax rules of the language. Syntax errors are detected by the interpreter or compiler at the time of parsing the code, and they prevent the code from being executed.
These errors occur because the written code does not conform to the grammatical rules of Python, making it impossible for the interpreter to understand and execute the commands.
Common Causes of Syntax Errors
Following are the common causes of syntax errors −Missing colons (:) after control flow statements (e.g., if, for, while) − Colons are used to define the beginning of an indented block, such as in functions, loops, and conditionals.
Open Compiler
# Error: Missing colon (:) after the if statementifTrueprint("This will cause a syntax error")
Incorrect indentation − Python uses indentation to define the structure of code blocks. Incorrect indentation can lead to syntax errors.
Open Compiler
# Error: The print statement is not correctly indenteddefexample_function():print("This will cause a syntax error")
Misspelled keywords or incorrect use of keywords.
Open Compiler
# Error: 'print' is misspelled as 'prnt'
prnt("Hello, World!")
Unmatched parentheses, brackets, or braces − Python requires that all opening parentheses (, square brackets [, and curly braces { have corresponding closing characters ), ], and }.
Open Compiler
# Error: The closing parenthesis is missing.print("This will cause a syntax error"
Learn Python in-depth with real-world projects through our Python certification course. Enroll and become a certified expert to boost your career.
How to Identify Syntax Errors
Identifying syntax errors in Python can sometimes be easy, especially when you get a clear error message from the interpreter. However, other times, it can be a bit tricky. Here are several ways to help you identify and resolve syntax errors effectively −
Reading Error Messages
When you run a Python script, the interpreter will stop execution and display an error message if it encounters a syntax error. Understanding how to read these error messages is very important.
Example Error Message
File "script.py", line 1print("Hello, World!"^
SyntaxError: EOL while scanning string literal
This error message can be broken down into parts −
File “script.py”: Indicates the file where the error occurred.
line 1: Indicates the line number in the file where the interpreter detected the error.
print(“Hello, World!”: Shows the line of code with the error.
^: Points to the location in the line where the error was detected.
Using an Integrated Development Environment (IDE)
IDEs are helpful in identifying syntax errors as they often provide real-time feedback. Here are some features of IDEs that helps in identifying syntax errors −
Syntax Highlighting: IDEs highlight code syntax in different colors. If a part of the code is incorrectly colored, it may indicate a syntax error.
Linting: Tools like pylint or flake8 check your code for errors and stylistic issues.
Error Underlining: Many IDEs underline syntax errors with a red squiggly line.
Tooltips and Error Messages: Hovering over the underlined code often provides a tooltip with a description of the error.
Popular IDEs with these features include PyCharm, Visual Studio Code, and Jupyter Notebook.
Running Code in Small Chunks
If you have a large script, it can be useful to run the code in smaller chunks. This can help isolate the part of the code causing the syntax error.
For example, if you have a script with multiple functions and you get a syntax error, try running each function independently to narrow down where the error might be.
Using Version Control
Version control systems like Git can help you track changes to your code. If you encounter a syntax error, you can compare the current version of the code with previous versions to see what changes might have introduced the error.
Fixing Syntax Errors
Fixing syntax errors in Python involves understanding the error message provided by the interpreter, identifying the exact issue in the code, and then making the necessary corrections. Here is a detailed guide on how to systematically approach and fix syntax errors −
Read the Error Message Carefully
Python’s error messages are quite informative. They indicate the file name, line number, and the type of syntax error −
Example Error Message
Assume we have written a print statement as shown below −
print("Hello, World!"
The following message indicates that there is a syntax error on line 1, showing that somewhere in the code, a parenthesis was left unclosed, which leads to a syntax error.
File "/home/cg/root/66634a37734ad/main.py", line 1print("Hello, World!"^
SyntaxError:'(' was never closed
To fix this error, you need to ensure that every opening parenthesis has a corresponding closing parenthesis. Here is the corrected code −
Open Compiler
print("Hello, World!")
Locate the Error
To locate the error, you need to go to the line number mentioned in the error message. Additionally, check not only the indicated line but also the lines around it, as sometimes the issue might stem from previous lines.
Understand the Nature of the Error
To understand the nature of the error, you need to identify what type of syntax error it is (e.g., missing parenthesis, incorrect indentation, missing colon, etc.). Also, refer to common syntax errors and their patterns.