Delete Set public Set private Add tags Delete tags
  Add tag   Cancel
  Delete tag   Cancel
  • • DevOps notes •
  •  
  • AI
  • Tags
  • Login

Context managers/shaare/wo-q7g

  • python
  • python

Context Managers

  • When opening files or acquiring locks, resources must be released even if errors occur.
  • Manual try...finally ensures cleanup but adds boilerplate and potential for mistakes.
  • Forgetting to initialize the resource variable or to call cleanup in every exit path leads to leaks, deadlocks, or corrupted data.
  • Cleaner patterns reduce noise and risk in automation scripts.
f = None

try:
    f = open("my_log.txt", "w")
    f.write("First line\n")
    # Simulate an error
    result = 1 / 0
    f.write("Second line\n")
except:
    print("Error has occurred.")
finally:
    if f:
        print("Closing file.")
        f.close()

print(f"File closed: {f.closed}")

The with Statement Simplifies Cleanup

  • The with statement handles setup and teardown automatically for context managers.
  • For file I/O, with open(...) as f: guarantees f.close() on block exit, even if an exception is raised.
  • Syntax is concise and idiomatic, reducing boilerplate and improving readability.

Common Context Manager Examples

  • Files: with open(...) as f: for automatic file closing.
  • Locks: with threading.Lock(): acquires and releases locks safely.
  • Tempfiles/Dirs: with tempfile.TemporaryDirectory() as d: creates and cleans up temporary directories.
  • Context managers from the standard library cover most resource-management needs.
f = None

try:
    with open("my_log.txt", "w") as f:
        f.write("First line\n")
        # Simulate an error
        result = 1 / 0
        f.write("Second line\n")
except:
    print("Error has occurred.")

print(f"File closed: {f.closed}")
import tempfile, os

dir_name = None

with tempfile.TemporaryDirectory() as tempdir:
    print(f"Created temp dir: {tempdir}")

    dir_name = tempdir
    test_file = os.path.join(tempdir, "test.txt")

    with open(test_file, "w") as file:
        file.write("Hello from temp directory.")

    print(f"Files inside temp dir: {os.listdir(tempdir)}")

try:
    contents = os.listdir(dir_name)
    print(f"Contents of {dir_name}: {contents}")
except FileNotFoundError as e:
    print(f"Expected error accessing removed directory: {e}")

Custom Resource Management: Writing Context Managers

  • Whenever you need custom setup/teardown logic, you can write your own Context Manager.
  • A context manager ensures that teardown always runs, even if errors occur in the block.
  • Two approaches: implement __enter__/__exit__ in a class or use the simpler generator-based decorator.
class MyContextManager:
    def __init__(self, timeout):
        self.timeout = timeout

    def __enter__(self):
        print("Setup complete")
        return "a simple value"

    def __exit__(self, exception_type, exception_value, traceback):
        print(f"Teardown")

        # Commenting out since we replaced *args for explicit
        # exception_type, exception_value, traceback parameters

        # for arg in args:
        #     print(arg)

        return False

with MyContextManager(timeout=30) as cm:
    print(cm)
    print("Inside the block")
    raise ValueError("Simulated problem")

The @contextlib.contextmanager Decorator

  • Provided by the contextlib module to turn a generator into a context manager.
  • Decorated function needs exactly one yield.
  • Code before yield runs as __enter__; code after (or in finally) runs as __exit__.
  • Simplifies many common patterns without writing a full class.

Generator Structure for @contextmanager

  • Wrap the yield in try...finally to ensure teardown even on errors.
  • The value yielded is bound to as var in the with statement (if used).
  • You can catch exceptions inside the generator if you want to suppress them.
import os
from contextlib import contextmanager

@contextmanager
def change_directory(destination):
    """
    Temporarily switch into destination. If the directory does not exist,
    it is created just before the switch.

    Args:
        destination (str): Path to the directory that should become the working directory
    """

    origin_dir = os.getcwd()

    try:
        print(f"Changing into {destination}")
        os.makedirs(destination, exist_ok=True)
        os.chdir(destination)
        yield os.getcwd()
    finally:
        print(f"Reverting to original dir: {origin_dir}")
        os.chdir(origin_dir)

print(f"Start: {os.getcwd()}")

with change_directory("temp_dir") as new_dir:
    print(f"Inside: {new_dir}")

print(f"End: {os.getcwd()}")
1 month ago Permalink
cluster icon
  • Custom Exceptions: Tailoring Error Signals : Custom Exceptions: Tailoring Error Signals Built-in exceptions are great, but often too generic for application-specific failures. A custom excepti...
  • Parametrized Tests : Parametrized Tests Introduction Often, we need to test the same logic with different inputs and outputs, such as validating various IP address or hos...
  • Regex : Regex Essentials: Overview Regular expressions (regex) are a language for defining text search patterns. Python’s re module provides functions like...
  • Pytest Markers : Pytest Markers Markers are decorators (@pytest.mark.) applied to tests to attach metadata. Built-in markers like skip, skipif, xfail, and parametrize...
  • Log Levels in Practice : Log Levels in Practice Python defines five standard levels with increasing severity: DEBUG (10): Detailed diagnostic information. INFO (20): Confirm...


(97)
Filter untagged links
Fold Fold all Expand Expand all Are you sure you want to delete this link? Are you sure you want to delete this tag? The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community