Hone logo
Hone
Problems

Resource Management with Context Managers

Context managers in Python provide a clean and reliable way to manage resources like files, network connections, or database cursors. They ensure that resources are properly acquired and released, even in the presence of exceptions, promoting robust and maintainable code. This challenge will guide you through creating your own context managers to handle resource allocation and deallocation effectively.

Problem Description

You are tasked with creating two custom context managers: FileWrapper and DatabaseConnection.

FileWrapper: This context manager should wrap a file object. When entered, it should print "Opening file...". When exited (either normally or due to an exception), it should print "Closing file..." and then close the file.

DatabaseConnection: This context manager simulates a database connection. When entered, it should print "Connecting to database...". When exited, it should print "Closing database connection..." and then call a disconnect() method (which you'll define within the class). The disconnect() method should simply print "Database connection closed.".

You must implement both context managers using the __enter__ and __exit__ methods. The __enter__ method should return the resource (file object or the DatabaseConnection instance itself). The __exit__ method should handle the cleanup and exception handling.

Key Requirements:

  • Both context managers must handle exceptions gracefully. If an exception occurs within the with block, the __exit__ method should still be called to ensure proper cleanup.
  • The DatabaseConnection context manager should demonstrate the use of the __exit__ method's arguments (exc_type, exc_val, exc_tb) to potentially log or handle exceptions. For this challenge, simply print the exception type and value if an exception occurred.
  • The context managers should be reusable and not rely on global state.

Expected Behavior:

When used with a with statement, the context managers should execute the appropriate "opening" and "closing" messages, and perform the necessary cleanup actions. Exceptions within the with block should be caught and handled by the __exit__ method.

Examples

Example 1: FileWrapper

Input:
with FileWrapper("my_file.txt", "w") as f:
    f.write("Hello, world!")
    raise ValueError("Simulated error")

Output:
Opening file...
Closing file...
ValueError: Simulated error

Explanation: The file is opened, "Hello, world!" is written, a ValueError is raised, the __exit__ method is called, printing "Closing file...", and the exception is re-raised.

Example 2: DatabaseConnection

Input:
with DatabaseConnection() as db:
    print("Inside database context")
    raise TypeError("Database error")

Output:
Connecting to database...
Inside database context
Closing database connection...
Database connection closed.
TypeError: Database error

Explanation: The database connection is established, "Inside database context" is printed, a TypeError is raised, the __exit__ method is called, printing "Closing database connection..." and "Database connection closed.", and the exception is re-raised.

Example 3: No Exception

Input:
with FileWrapper("my_file.txt", "w") as f:
    f.write("Hello, world!")

Output:
Opening file...
Closing file...

Explanation: The file is opened, "Hello, world!" is written, the __exit__ method is called, printing "Closing file...", and no exception is raised.

Constraints

  • The FileWrapper should accept a filename and mode as arguments to its constructor.
  • The DatabaseConnection should not accept any arguments to its constructor.
  • The __exit__ method in DatabaseConnection must handle the exception arguments (exc_type, exc_val, exc_tb) by printing the exception type and value if an exception occurred.
  • All file operations must be performed within the with block.
  • The disconnect() method in DatabaseConnection should simply print "Database connection closed.".

Notes

  • Remember that the __exit__ method receives three arguments: exc_type, exc_val, and exc_tb. exc_type is the exception type (or None if no exception occurred), exc_val is the exception instance, and exc_tb is the traceback object.
  • Consider how to ensure that the file is properly closed even if an exception occurs during file writing.
  • Think about the purpose of context managers and how they contribute to cleaner and more reliable code.
  • The __enter__ method should return a value that can be assigned to a variable in the with statement. In this case, it's the file object or the DatabaseConnection instance.
Loading editor...
python