@contextmanager def get_state(name): print("entering:", name) yield name print("exiting :", name)
# multiple get_state can be nested like this with get_state("A") as A, get_state("B") as B, get_state("C") as C: print("inside with statement:", A, B, C) entering: A entering: B entering: C inside with statement: A B C exiting : C exiting : B exiting : A
@contextmanager def ab(a, b): with a("A") as A, b("B") as B: yield (A, B)
1 2 3 4 5 6 7
with ab(a, b) as AB: print("Inside the composite context manager:", AB) entering a: A entering b: B Inside the composite context manager: ('A', 'B') exiting b: B exiting a: A
@contextmanager def ab(cms, args): with ExitStack() as stack: yield [stack.enter_context(cm(arg)) for cm, arg in zip(cms, args)] with ab((a, b), ("A", "B")) as AB: print("Inside the composite context manager:", AB) entering a: A entering b: B Inside the composite context manager: ['A', 'B'] exiting b: B exiting a: A ExitStack如果您要优雅地管理多个资源,也可以使用它。例如,假设您需要根据目录中多个文件的内容创建一个列表。让我们看看,如何通过强大的资源管理来避免意外的内存泄漏。
from contextlib import ExitStack from pathlib import Path
# ExitStack ensures all files are properly closed after o/p with ExitStack() as stack: streams = ( stack.enter_context(open(fname, "r")) for fname in Path("src").rglob("*.py") ) contents = [f.read() for f in streams]
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from contextlib import contextmanager
# an Engine, which the Session will use for connection resources some_engine = create_engine("sqlite://")
# create a configured "Session" class Session = sessionmaker(bind=some_engine)
@contextmanager def session_scope(): """Provide a transactional scope around a series of operations.""" session = Session() try: yield session session.commit() except: session.rollback() raise finally: session.close()
@errhandler() def div(a, b): return a // b div("b", 0) This is a custom TypeError message. ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-43-65497ed57253> in <module> ----> 1 div('b',0)
/usr/lib/python3.8/contextlib.py in inner(*args, **kwds) 73 def inner(*args, **kwds): 74 with self._recreate_cm(): ---> 75 return func(*args, **kwds) 76 return inner 77
<ipython-input-42-b7041bcaa9e6> in div(a, b) 1 @errhandler() 2 def div(a, b): ----> 3 return a // b
TypeError: unsupported operand type(s) for //: 'str' and 'int'
class Calculation: """Dummy class for demonstrating exception decoupling with contextmanager."""
def __init__(self, a, b): self.a = a self.b = b
@contextmanager def errorhandler(self): try: yield except ZeroDivisionError: print( f"Custom handling of Zero Division Error! Printing " "only 2 levels of traceback.." ) logging.exception("ZeroDivisionError")
def main_func(self): """Function that we want to save from nasty error handling logic."""
with self.errorhandler(): return self.a / self.b
obj = Calculation(2, 0) print(obj.main_func())
这将返回
1 2 3 4 5 6 7 8 9 10 11
(asctime)s [ERROR] ZeroDivisionError Traceback (most recent call last): File "<ipython-input-44-ff609edb5d6e>", line 25, in errorhandler yield File "<ipython-input-44-ff609edb5d6e>", line 37, in main_func return self.a / self.b ZeroDivisionError: division by zero
Custom handling of Zero Division Error! Printing only 2 levels of traceback.. None
with requests.Session() as session: session.get("http://httpbin.org/cookies/set/sessioncookie/123456789") response = session.get("http://httpbin.org/cookies") print(response.text)