Перейти к содержанию

Context manager

An object which controls the environment seen in a with statement by defining __enter__() and __exit__() methods.

See PEP 343.

Examples

  1. Order of execution of magic methods in a class:

    my_context_manager.py
    class MyClass(object):
    
        def __init__(self):
            print('__init__')
            self.name = 'Guido van Rossum'
    
        def __enter__(self):
            print('__enter__')
            return self
    
        def __exit__(self, type, value, traceback):
            print('__exit__')
    
        def __del__(self):
            print('__del__')
    
    with MyClass() as mc:
        print('body')
        print(mc.name)
    
    output
    __init__
    __enter__
    body
    Guido van Rossum
    __exit__
    __del__
    

  2. A useful example could be a database connection object, which then automagically closes the connection once the corresponding with-statement goes out of scope:

    class DatabaseConnection(object):
    
        def __enter__(self):
            # make a database connection and return it
            ...
            return self.dbconn
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            # make sure the dbconnection gets closed
            self.dbconn.close()
            ...
    
    with DatabaseConnection() as mydbconn:
        # do stuff
        pass
    

  3. A template for opening a file that ensures the file is closed when the block is left:

    from contextlib import contextmanager
    
    @contextmanager
    def opened_w_error(filename, mode="r"):
        try:
            f = open(filename, mode)
        except IOError, err:
            yield None, err
        else:
            try:
                yield f, None
            finally:
                f.close()
    
    with opened_w_error("/etc/passwd", "a") as (f, err):
        if err:
            print "IOError:", err
        else:
            f.write("guido::0:0::/:/bin/sh\n")
    

  4. A template for committing or rolling back a database transaction:

    @contextmanager
    def transaction(db):
        db.begin()
        try:
            yield None
        except:
            db.rollback()
            raise
        else:
            db.commit()
    

  5. A generic "object-closing" context manager:

    class closing(object):
        def __init__(self, obj):
            self.obj = obj
        def __enter__(self):
            return self.obj
        def __exit__(self, *exc_info):
            try:
                close_it = self.obj.close
            except AttributeError:
                pass
            else:
                close_it()
    
    # emulate opening():
    with closing(open("argument.txt")) as contradiction:
        for line in contradiction:
            print (line)
    

PEP 343 -- The «with» Statement

A new statement is proposed with the syntax:

with EXPR as VAR:  # The "as VAR" part is optional.
    BLOCK
, where:

  1. EXPR is an arbitrary expression (but not an expression-list);
  2. VAR is a single assignment target.

The translation of the above statement is:

mgr = (EXPR)
exit = type(mgr).__exit__  # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
    try:
        VAR = value  # Only if "as VAR" is present
        BLOCK
    except:
        # The exceptional case is handled here
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
        # The exception is swallowed if exit() returns true
finally:
    # The normal and non-local-goto cases are handled here
    if exc:
        exit(mgr, None, None, None)

Context Manager Types

With Statement Context Managers

A context manager is an object that defines the runtime context to be established when executing a with statement.

The context manager handles the entry into, and the exit from, the desired runtime context for the execution of the block of code. Context managers are normally invoked using the with statement, but can also be used by directly invoking their methods.

Typical uses of context managers include:

  1. saving and restoring various kinds of global state;
  2. locking and unlocking resources;
  3. closing opened files, etc.

Enter the runtime context related to this object: object.__enter__(self). The with statement will bind this method’s return value to the target(s) specified in the as clause of the statement, if any.

Exit the runtime context related to this object: object.__exit__(self, exc_type, exc_value, traceback). The parameters describe the exception that caused the context to be exited. If the context was exited without an exception, all three arguments will be None.

Note

Note that __exit__() methods should not reraise the passed-in exception; this is the caller’s responsibility.

The with statement

The with statement is used to wrap the execution of a block with methods defined by a context manager. This allows common tryexceptfinally usage patterns to be encapsulated for convenient reuse.