CodeGym /Courses /Python SELF EN /The with Statement

The with Statement

Python SELF EN
Level 21 , Lesson 3
Available

4.1 Closing a File and Handling Errors

Sometimes errors or exceptions occur when reading a file, and the file remains open. This can potentially lead to memory leaks or file handler leaks. So, you need to wrap file operations in a try-except block.

Let's say you had a code like this:


file = open('example.txt', 'a') # Open the file
file.write("This is a new line added to the file.")
file.close()  # Close the file

You should wrap it in a try-except block:


try:
    file = open('example.txt', 'a')  # Open the file
    file.write("This is a new line added to the file.")
    file.close()  # Close the file
except FileNotFoundError:
    print("File not found")
    file.close()  # Close the file

To avoid writing the close() method twice, you can move it to the finally block:


try:
    file = open('example.txt', 'a')  # Open the file
    file.write("This is a new line added to the file.")
except FileNotFoundError:
    print("File not found")
finally:
    file.close()  # Close the file

This code looks nice, but… it doesn’t work since the variable file is only defined in the try block and is not accessible from the except and finally blocks.

So we need to define the variable one level higher:


file = None
try:
    file = open('example.txt', 'a')  # Open the file
    file.write("This is a new line added to the file.")
except FileNotFoundError:
    print("File not found")
finally:
    file.close()  # Close the file

This solution is better, but it still has downsides. For instance, if the file is never actually opened, file will remain None. Then attempting to close the file will result in an error — you'll be trying to call the close() method on a non-existent object.

So, we need to perform a check before calling the close() method:


file = None
try:
    file = open('example.txt', 'a')  # Open the file
    file.write("This is a new line added to the file.")
except FileNotFoundError:
    print("File not found")
finally:
    if file:
        file.close()  # Close the file

If you're surprised that 3 lines of code turned into 9, you're not alone. Luckily, there's already a ready solution for this problem, which we'll discuss next.

4.2 The with Statement

The with statement in Python provides a convenient way to manage resources, like files, ensuring they are automatically closed after the with block is executed. This simplifies the code and prevents resource leaks, such as unclosed files.

The general syntax of the with statement:


with expression as variable:
    work with the variable

The with statement is used for wrapping the execution of a block of code with a context manager. When using the with statement, Python automatically calls the __enter__() and __exit__() methods of the context manager object, which simplifies resource management.

Example of using with for file operations:


with open('example.txt', 'w') as file:
    file.write("Hello, World!\n")
    file.write("This is a test file.\n")

In this example, the file example.txt is opened in write mode, and the file name is associated with the variable file. The code block inside with automatically closes the file after all write operations are completed.

4.3 Automatic File Closing

One of the main advantages of using the with statement is the automatic closing of the file once the code block is completed. This happens even if an exception occurs, making the code more secure and reliable.

Example of automatic file closing:


try:
    with open('example.txt', 'w') as file:
        file.write("Hello, World!\n")
        file.write("This is a test file.\n")
        # Raise an exception to check that the file still closes
        raise Exception("Something went wrong")
except Exception as e:
    print(f"Caught an exception: {e}")
# At this point, the file is already closed

Always use the with statement for file operations. It's simple and helps avoid a bunch of errors.

4.4 Under the Hood of the with Statement

The operation of the with statement is based on the __enter__() and __exit__() methods, which must be implemented in the class used as a context manager.

For an object to be usable with the with statement, it must implement the __enter__() and __exit__() methods. These methods define behavior upon entering and exiting the context.

The __enter__() Method

The __enter__() method is called upon entering the with block. It initializes the resource and returns the object that will be bound to the variable specified after as.

The __exit__() Method

The __exit__() method is called upon exiting the with block. It performs final actions, such as freeing resources or closing files. The method accepts three arguments: exc_type, exc_val, and exc_tb, which contain information about an exception, if one occurred.

  • exc_type: the exception type (e.g., ZeroDivisionError).
  • exc_val: the exception value (e.g., the error message).
  • exc_tb: the exception traceback.

If the __exit__() method returns True, the exception will be suppressed. If it returns False, the exception will be re-raised.

Example:


class MyContextManager:
    def __enter__(self):
        print("Entering the context")
        return self
        
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            print(f"An exception occurred: {exc_type}, {exc_val}")
        return False  # Exception is not suppressed
        
with MyContextManager() as manager:
    print("Inside the with block")
2
Task
Python SELF EN, level 21, lesson 3
Locked
Error handling when working with files
Error handling when working with files
2
Task
Python SELF EN, level 21, lesson 3
Locked
Using the with statement for file operations
Using the with statement for file operations
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION