contextlib --- with æã³ã³ããã¹ãçšãŠãŒãã£ãªãã£Â¶
ãœãŒã¹ã³ãŒã: Lib/contextlib.py
ãã®ã¢ãžã¥ãŒã«ã¯ with æã«é¢ããäžè¬çãªã¿ã¹ã¯ã®ããã®ãŠãŒãã£ãªãã£ãæäŸããŸãã詳ããæ
å ±ã¯ã ã³ã³ããã¹ããããŒãžã£å ãš withæãšã³ã³ããã¹ããããŒãžã£ ãåç
§ããŠãã ããã
ãŠãŒãã£ãªãã£Â¶
以äžã®é¢æ°ãšã¯ã©ã¹ãæäŸããŠããŸã:
- class contextlib.AbstractContextManager¶
An abstract base class for classes that implement
__enter__()and__exit__(). A default implementation for__enter__()is provided which returnsselfwhile__exit__()is an abstract method which by default returnsNone. See also the definition of ã³ã³ããã¹ããããŒãžã£å.Added in version 3.6.
- class contextlib.AbstractAsyncContextManager¶
An abstract base class for classes that implement
__aenter__()and__aexit__(). A default implementation for__aenter__()is provided which returnsselfwhile__aexit__()is an abstract method which by default returnsNone. See also the definition of éåæã³ã³ããã¹ããããŒãžã£ (Asynchronous Context Manager).Added in version 3.7.
- @contextlib.contextmanager¶
ãã®é¢æ°ã¯
withæã³ã³ããã¹ããããŒãžã£ã®ãã¡ã¯ããªé¢æ°ãå®çŸ©ããããã«å©çšã§ãã ãã³ã¬ãŒã¿ ã§ããæ°ããã¯ã©ã¹ã__enter__()ãš__exit__()ã¡ãœãããå¥ã ã«å®çŸ©ããªããŠãããã¡ã¯ããªé¢æ°ãå®çŸ©ããããšãã§ããŸããWhile many objects natively support use in with statements, sometimes a resource needs to be managed that isn't a context manager in its own right, and doesn't implement a
close()method for use withcontextlib.closing.ãªãœãŒã¹ãæ£ãã管çããããä¿èšŒããæœè±¡çãªäŸã¯ä»¥äžã®ãããªãã®ã§ããã:
from contextlib import contextmanager @contextmanager def managed_resource(*args, **kwds): # Code to acquire resource, e.g.: resource = acquire_resource(*args, **kwds) try: yield resource finally: # Code to release resource, e.g.: release_resource(resource)
ãã®ãšãã颿°ã¯æ¬¡ã®ããã«äœ¿ãããšãã§ããŸã:
>>> with managed_resource(timeout=3600) as resource: ... # Resource is released at the end of this block, ... # even if code in the block raises an exception
ãã³ã¬ãŒã察象ã®é¢æ°ã¯åŒã³åºããããšãã« ãžã§ãã¬ãŒã¿-ã€ãã¬ãŒã¿ãè¿ãå¿ èŠããããŸãããã®ã€ãã¬ãŒã¿ã¯å¿ ãå€ã1〠yield ããªããã°ãªããŸããã
withæã®asç¯ãååšãããªãããã®å€ã¯ as ç¯ã®ã¿ãŒã²ãããžæçžãããããšã«ãªããŸãããžã§ãã¬ãŒã¿ã yield ãå®è¡ããç®æã§
withæã®ãã¹ãããããããã¯ãå®è¡ãããŸãããããã¯ããæããåŸã§ãžã§ãã¬ãŒã¿ã¯åéãããŸãããããã¯å ã§åŠçãããªãäŸå€ãçºçããå Žåã¯ããžã§ãã¬ãŒã¿å éšã® yield ãå®è¡ããç®æã§äŸå€ãåéåºãããŸãããªã®ã§ã(ããããã°) ãšã©ãŒãææããããã¯ãªãŒã³ã¢ããåŠçã確å®ã«å®è¡ãããããããã«ãtry...except...finallyæ§æã䜿çšã§ããŸããäŸå€ãææããç®çãã(å®å šã«äŸå€ãæå¶ããŠããŸãã®ã§ã¯ãªã) åã«äŸå€ã®ãã°ããšãããããããã¯ããã¢ã¯ã·ã§ã³ãå®è¡ãããããªãããžã§ãã¬ãŒã¿ã¯ãã®äŸå€ãåéåºããªããã°ãªããŸãããäŸå€ãåéåºããªãå Žåããžã§ãã¬ãŒã¿ã®ã³ã³ããã¹ããããŒãžã£ã¯withæã«å¯ŸããŠäŸå€ãåŠçãããããšã瀺ããwithæã®çŽåŸã®æããå®è¡ãåéããŸãã@contextmanagerusesContextDecoratorso the context managers it creates can be used as decorators as well as inwithstatements. When used as a decorator, a new generator instance is implicitly created on each function call (this allows the otherwise "one-shot" context managers created by@contextmanagerto meet the requirement that context managers support multiple invocations in order to be used as decorators).ããŒãžã§ã³ 3.2 ã§å€æŽ:
ContextDecoratorã®äœ¿çšã
- @contextlib.asynccontextmanager¶
Similar to
@~contextlib.contextmanager, but creates an asynchronous context manager.ãã®é¢æ°ã¯
async withæã®ããã®éåæã³ã³ããã¹ããããŒãžã£ã®ãã¡ã¯ããªé¢æ°ãå®çŸ©ããããã«å©çšã§ãããã³ã¬ãŒã¿ (decorator) ã§ããæ°ããã¯ã©ã¹ã__aenter__()ãš__aexit__()ã¡ãœãããåå¥ã«å®çŸ©ããå¿ èŠã¯ãããŸããããã®ãã³ã¬ãŒã¿ã¯éåæãžã§ãã¬ãŒã¿ (asynchronous generator) 颿°ã«é©çšããªããã°ãªããŸãããç°¡åãªäŸ:
from contextlib import asynccontextmanager @asynccontextmanager async def get_connection(): conn = await acquire_db_connection() try: yield conn finally: await release_db_connection(conn) async def get_all_users(): async with get_connection() as conn: return conn.query('SELECT ...')
Added in version 3.7.
Context managers defined with
@asynccontextmanagercan be used either as decorators or withasync withstatements:import time from contextlib import asynccontextmanager @asynccontextmanager async def timeit(): now = time.monotonic() try: yield finally: print(f'it took {time.monotonic() - now}s to run') @timeit() async def main(): # ... async code ...
When used as a decorator, a new generator instance is implicitly created on each function call. This allows the otherwise "one-shot" context managers created by
@asynccontextmanagerto meet the requirement that context managers support multiple invocations in order to be used as decorators.ããŒãžã§ã³ 3.10 ã§å€æŽ: Async context managers created with
@asynccontextmanagercan be used as decorators.
- contextlib.closing(thing)¶
ãããã¯ã®å®äºæã« thing ã close ããã³ã³ããã¹ããããŒãžã£ãè¿ããŸããããã¯åºæ¬çã«ä»¥äžãšç䟡ã§ã:
from contextlib import contextmanager @contextmanager def closing(thing): try: yield thing finally: thing.close()
ãããŠãæç€ºçã«
pageã close ããå¿ èŠãªãã«ã次ã®ããã«æžãããšãã§ããŸã:from contextlib import closing from urllib.request import urlopen with closing(urlopen('https://www.python.org')) as page: for line in page: print(line)
pageãæç€ºçã« close ããå¿ èŠã¯ç¡ãããšã©ãŒãçºçããå Žåã§ããwithãããã¯ãåºããšãã«page.close()ãåŒã°ããŸããæ³šé
Most types managing resources support the context manager protocol, which closes thing on leaving the
withstatement. As such,closing()is most useful for third party types that don't support context managers. This example is purely for illustration purposes, asurlopen()would normally be used in a context manager.
- contextlib.aclosing(thing)¶
ãããã¯ã®å®äºæã« thing ã®
aclose()ã¡ãœãããåŒã³åºããããªéåæã³ã³ããã¹ããããŒãžã£ãè¿ããŸããããã¯åºæ¬çã«ä»¥äžãšç䟡ã§ã:from contextlib import asynccontextmanager @asynccontextmanager async def aclosing(thing): try: yield thing finally: await thing.aclose()
éèŠãªããšã¯ãããšãã°æ¬¡ã®äŸã®ããã«
breakãäŸå€ã«ãã£ãŠæ©æã«ãããã¯ãçµäºããå Žåã«ãaclosing()ã¯éåæãžã§ãã¬ãŒã¿ã®æ±ºå®è«çãªã¯ãªãŒã³ã¢ããããµããŒãããããšã§ã:from contextlib import aclosing async with aclosing(my_generator()) as values: async for value in values: if value == 42: break
ãã®ãã¿ãŒã³ã¯ããžã§ãã¬ãŒã¿ã®éåæãªçµäºã®ã³ãŒããã€ãã¬ãŒã·ã§ã³åŠçãšåãã³ã³ããã¹ãã®äžã§å®è¡ãããããšãä¿èšŒããŸã (ããªãã¡äŸå€ãšã³ã³ããã¹ã倿°ã¯æåŸ éãã«åäœãããŸããžã§ãã¬ãŒã¿ãäŸåããã¿ã¹ã¯ã®å¯¿åœãå°œããããšã«çµäºã®ã³ãŒããå®è¡ãããããšããããŸãã)ã
Added in version 3.10.
- contextlib.nullcontext(enter_result=None)¶
Return a context manager that returns enter_result from
__enter__(), but otherwise does nothing. It is intended to be used as a stand-in for an optional context manager, for example:def myfunction(arg, ignore_exceptions=False): if ignore_exceptions: # Use suppress to ignore all exceptions. cm = contextlib.suppress(Exception) else: # Do not ignore any exceptions, cm has no effect. cm = contextlib.nullcontext() with cm: # Do something
enter_result ã䜿ã£ãäŸã§ã:
def process_file(file_or_path): if isinstance(file_or_path, str): # If string, open file cm = open(file_or_path) else: # Caller is responsible for closing file cm = nullcontext(file_or_path) with cm as file: # Perform processing on the file
éåæã³ã³ããã¹ããããŒãžã£ ã®ä»£åœ¹ãšããŠäœ¿ãããšãã§ããŸã:
async def send_http(session=None): if not session: # If no http session, create it with aiohttp cm = aiohttp.ClientSession() else: # Caller is responsible for closing the session cm = nullcontext(session) async with cm as session: # Send http requests with session
Added in version 3.7.
ããŒãžã§ã³ 3.10 ã§å€æŽ: éåæã³ã³ããã¹ããããŒãžã£ (asynchronous context manager) ã®ãµããŒãã远å ãããŸããã
- contextlib.suppress(*exceptions)¶
withæã®å éšã§æå®ãããäŸå€ã®çºçãæããã³ã³ããã¹ããããŒãžã£ãè¿ããŸããwithæã®åŸã«ç¶ãæåã®æããåŠçãåéãããŸããã»ãã®å®å šã«äŸå€ãæå¶ããã¡ã«ããºã åæ§ããã®ã³ã³ããã¹ããããŒãžã£ã¯ãé»ã£ãŠããã°ã©ã å®è¡ãç¶ããããšãæ£ããããšã§ãããšããã£ãŠãããéåžžã«éå®çãªãšã©ãŒãã«ããŒãã以äžã®äœ¿ãæ¹ã¯ããŠã¯ãããŸããã
äŸãã°:
from contextlib import suppress with suppress(FileNotFoundError): os.remove('somefile.tmp') with suppress(FileNotFoundError): os.remove('someotherfile.tmp')
ããã¯ä»¥äžãšç䟡ã§ã:
try: os.remove('somefile.tmp') except FileNotFoundError: pass try: os.remove('someotherfile.tmp') except FileNotFoundError: pass
ãã®ã³ã³ããã¹ããããŒãžã£ã¯ åå ¥å¯èœ(ãªãšã³ãã©ã³ã) ã§ãã
If the code within the
withblock raises aBaseExceptionGroup, suppressed exceptions are removed from the group. Any exceptions of the group which are not suppressed are re-raised in a new group which is created using the original group'sderive()method.Added in version 3.4.
ããŒãžã§ã³ 3.12 ã§å€æŽ:
suppressnow supports suppressing exceptions raised as part of aBaseExceptionGroup.
- contextlib.redirect_stdout(new_target)¶
Context manager for temporarily redirecting
sys.stdoutto another file or file-like object.This tool adds flexibility to existing functions or classes whose output is hardwired to stdout.
For example, the output of
help()normally is sent to sys.stdout. You can capture that output in a string by redirecting the output to anio.StringIOobject. The replacement stream is returned from the__enter__()method and so is available as the target of thewithstatement:with redirect_stdout(io.StringIO()) as f: help(pow) s = f.getvalue()
help()ã®åºåããã£ã¹ã¯äžã®ãã¡ã€ã«ã«éãããã«ã¯ãåºåãéåžžã®ãã¡ã€ã«ã«ãªãã€ã¬ã¯ãããŸã:with open('help.txt', 'w') as f: with redirect_stdout(f): help(pow)
help()ã®åºåãæšæºãšã©ãŒåºå (sys.stderr) ã«éãã«ã¯ä»¥äžã®ããã«ããŸã:with redirect_stdout(sys.stderr): help(pow)
sys.stdoutã®ã·ã¹ãã å šäœã«ãããå¯äœçšã«ããããã®ã³ã³ããã¹ããããŒãžã£ã¯ã©ã€ãã©ãªã³ãŒãããã«ãã¹ã¬ããã¢ããªã±ãŒã·ã§ã³ã§ã®äœ¿çšã«ã¯é©ããŠããŸããããŸãããµãããã»ã¹ã®åºåã«å¯ŸããŠã广ããããŸããããã®ãããªå¶éã¯ãããŸãããããã§ãå€ãã®ãŠãŒãã£ãªãã£ã¹ã¯ãªããã«å¯ŸããŠæçšãªã¢ãããŒãã§ãããã®ã³ã³ããã¹ããããŒãžã£ã¯ åå ¥å¯èœ(ãªãšã³ãã©ã³ã) ã§ãã
Added in version 3.4.
- contextlib.redirect_stderr(new_target)¶
Similar to
redirect_stdout()but redirectingsys.stderrto another file or file-like object.ãã®ã³ã³ããã¹ããããŒãžã£ã¯ åå ¥å¯èœ(ãªãšã³ãã©ã³ã) ã§ãã
Added in version 3.5.
- contextlib.chdir(path)¶
çŸåšã®äœæ¥ãã£ã¬ã¯ããªã倿Žãããã©ã¬ã«éå®å šãªã³ã³ããã¹ããããŒãžã£ã§ããã°ããŒãã«ãªç¶æ ã§ããäœæ¥ãã£ã¬ã¯ããªã倿Žãããããã»ãšãã©ã®ãã«ãã¹ã¬ãããŸãã¯éåæã®ã³ã³ããã¹ãã«å¯Ÿããå©çšã¯é©åã§ã¯ãããŸããããŸããããã°ã©ã ã®å®è¡æš©éãäžæçã«æŸæ£ãããžã§ãã¬ãŒã¿ã®ãããªãçŽç·çã§ãªãã³ãŒããå®è¡ããå Žåãé©åã§ã¯ãããŸãã -- æç¢ºã«å¿ èŠã§ãªããããããã®ã³ã³ããã¹ããããŒãžã£ãã¢ã¯ãã£ããªç¶æ ã§ yield ãã¹ãã§ã¯ãããŸããã
ããã¯
chdir()ã®åçŽãªã©ãããŒã§ãã³ã³ããã¹ãã«å ¥ããšãã«çŸåšã®äœæ¥ãã£ã¬ã¯ããªã倿Žããçµäºæã«å ã®äœæ¥ãã£ã¬ã¯ããªã埩å ããŸãããã®ã³ã³ããã¹ããããŒãžã£ã¯ åå ¥å¯èœ(ãªãšã³ãã©ã³ã) ã§ãã
Added in version 3.11.
- class contextlib.ContextDecorator¶
ã³ã³ããã¹ããããŒãžã£ããã³ã¬ãŒã¿ãšããŠã䜿çšã§ããããã«ããåºåºã¯ã©ã¹ã§ãã
Context managers inheriting from
ContextDecoratorhave to implement__enter__()and__exit__()as normal.__exit__retains its optional exception handling even when used as a decorator.ContextDecoratoris used by@contextmanager, so you get this functionality automatically.ContextDecoratorã®äŸ:from contextlib import ContextDecorator class mycontext(ContextDecorator): def __enter__(self): print('Starting') return self def __exit__(self, *exc): print('Finishing') return False
ãã®ãšããã¯ã©ã¹ã¯æ¬¡ã®ããã«äœ¿ãããšãã§ããŸã:
>>> @mycontext() ... def function(): ... print('The bit in the middle') ... >>> function() Starting The bit in the middle Finishing >>> with mycontext(): ... print('The bit in the middle') ... Starting The bit in the middle Finishing
ããã¯æ¬¡ã®ãããªåœ¢ã®ã³ãŒãã«å¯Ÿããã·ã³ã¿ãã¯ã¹ã·ã¥ã¬ãŒã«ãªããŸã:
def f(): with cm(): # Do stuff
ContextDecoratorã䜿ããšä»£ããã«æ¬¡ã®ããã«æžããŸã:@cm() def f(): # Do stuff
ãã³ã¬ãŒã¿ãŒã䜿ããšã
cmã颿°ã®äžéšã§ã¯ãªãå šäœã«é©çšãããŠããããšãæç¢ºã«ãªããŸã (ã€ã³ãã³ãã¬ãã«ã1ã€ç¯çŽã§ããã®ãã¡ãªããã§ã)ããã§ã«åºåºã¯ã©ã¹ãæã£ãŠããã³ã³ããã¹ããããŒãžã£ãŒãã
ContextDecoratorã mixin ã¯ã©ã¹ãšããŠå©çšããããšã§æ¡åŒµã§ããŸã:from contextlib import ContextDecorator class mycontext(ContextBaseClass, ContextDecorator): def __enter__(self): return self def __exit__(self, *exc): return False
泚é
ãã³ã¬ãŒãããã颿°ãè€æ°ååŒã³åºããããã«ãå éšã®ã³ã³ããã¹ããããŒãžã£ãŒã¯è€æ°ã®
withæã«å¯Ÿå¿ããå¿ èŠããããŸããããã§ãªããªããæç€ºçãªwithæã颿°å ã§å©çšããã¹ãã§ããAdded in version 3.2.
- class contextlib.AsyncContextDecorator¶
Similar to
ContextDecoratorbut only for asynchronous functions.AsyncContextDecoratorã®äœ¿çšäŸ:from asyncio import run from contextlib import AsyncContextDecorator class mycontext(AsyncContextDecorator): async def __aenter__(self): print('Starting') return self async def __aexit__(self, *exc): print('Finishing') return False
ãã®ãšããã¯ã©ã¹ã¯æ¬¡ã®ããã«äœ¿ãããšãã§ããŸã:
>>> @mycontext() ... async def function(): ... print('The bit in the middle') ... >>> run(function()) Starting The bit in the middle Finishing >>> async def function(): ... async with mycontext(): ... print('The bit in the middle') ... >>> run(function()) Starting The bit in the middle Finishing
Added in version 3.10.
- class contextlib.ExitStack¶
ä»ã®ãç¹ã«ãªãã·ã§ã³ã§ãã£ããå ¥åã«äŸåãããããªã³ã³ããã¹ããããŒãžã£ãŒãã¯ãªãŒã³ã¢ãã颿°ãåçã«çµã¿åãããããã®ã³ã³ããã¹ããããŒãžã£ãŒã§ãã
äŸãã°ãè€æ°ã®ãã¡ã€ã«ã1ã€ã® with æã§ç°¡åã«æ±ãããšãã§ããŸã:
with ExitStack() as stack: files = [stack.enter_context(open(fname)) for fname in filenames] # All opened files will automatically be closed at the end of # the with statement, even if attempts to open files later # in the list raise an exception
The
__enter__()method returns theExitStackinstance, and performs no additional operations.åã€ã³ã¹ã¿ã³ã¹ã¯ç»é²ãããã³ãŒã«ããã¯ã®ã¹ã¿ãã¯ã管çããã€ã³ã¹ã¿ã³ã¹ã (æç€ºçã«ããããã¯
withæã®çµããã«æé»çã«) close ããããšãã«éé ã§ãããåŒã³åºããŸããã³ã³ããã¹ãã¹ã¿ãã¯ã®ã€ã³ã¹ã¿ã³ã¹ãæé»çã«ã¬ããŒãžã³ã¬ã¯ãããããšãã«ã¯ callback ã¯åŒã³åºãã ãŸãã ããã®ã¹ã¿ãã¯ã¢ãã«ã¯ã(file ãªããžã§ã¯ãã®ããã«)
__init__ã¡ãœããã§ãªãœãŒã¹ã確ä¿ããã³ã³ããã¹ããããŒãžã£ãŒãæ£ããæ±ãããã®ãã®ã§ããç»é²ãããã³ãŒã«ããã¯ãç»é²ã®éé ã§å®è¡ãããã®ã§ãè€æ°ã®ãã¹ãããã
withæãå©çšããã®ãšåãæ¯ãèããããŸããããã¯äŸå€åŠçã«ãé©çšãããŸããå åŽã®ã³ãŒã«ããã¯ãäŸå€ãæå¶ããã眮ãæãããããå Žåãå€åŽã®ã³ãŒã«ããã¯ã«ã¯æŽæ°ãããç¶æ ã«å¿ããåŒæ°ãæž¡ãããŸããããã¯æ£ãã exit callback ã® stack ãå·»ãæ»ãããã®ãæ¯èŒçäœã¬ãã«ãª API ã§ããã¢ããªã±ãŒã·ã§ã³ç¬èªã®ããé«ã¬ãã«ãªã³ã³ããã¹ããããŒãžã£ãŒãäœãããã®åºæ¿ãšããŠäœ¿ãã®ã«é©ããŠããŸãã
Added in version 3.3.
- enter_context(cm)¶
Enters a new context manager and adds its
__exit__()method to the callback stack. The return value is the result of the context manager's own__enter__()method.ã³ã³ããã¹ããããŒãžã£ãŒã¯ãæ®æ®µ
withæã§å©çšãããæãšåãããã«ãäŸå€ãæå¶ããããšãã§ããŸããããŒãžã§ã³ 3.11 ã§å€æŽ: cm ãã³ã³ããã¹ããããŒãžã£ã§ãªãã£ãå Žåã
AttributeErrorã®ä»£ããã«TypeErroräŸå€ãéåºããŸãã
- push(exit)¶
Adds a context manager's
__exit__()method to the callback stack.As
__enter__is not invoked, this method can be used to cover part of an__enter__()implementation with a context manager's own__exit__()method.If passed an object that is not a context manager, this method assumes it is a callback with the same signature as a context manager's
__exit__()method and adds it directly to the callback stack.By returning true values, these callbacks can suppress exceptions the same way context manager
__exit__()methods can.ãã®é¢æ°ã¯ãã³ã¬ãŒã¿ãšããŠã䜿ããããã«ãåãåã£ããªããžã§ã¯ãããã®ãŸãŸè¿ããŸãã
- callback(callback, /, *args, **kwds)¶
ä»»æã®é¢æ°ãšåŒæ°ãåãåããã³ãŒã«ããã¯ã¹ã¿ãã¯ã«è¿œå ããŸãã
ä»ã®ã¡ãœãããšç°ãªãããã®ã¡ãœããã§è¿œå ãããã³ãŒã«ããã¯ã¯äŸå€ãæå¶ããŸãã (äŸå€ã®è©³çŽ°ãæž¡ãããŸãã)ã
ãã®é¢æ°ã¯ãã³ã¬ãŒã¿ãšããŠã䜿ããããã«ãåãåã£ã callback ããã®ãŸãŸè¿ããŸãã
- pop_all()¶
ã³ãŒã«ããã¯ã¹ã¿ãã¯ãæ°ãã
ExitStackã€ã³ã¹ã¿ã³ã¹ã«ç§»ããŠããããè¿ããŸãããã®ã¡ãœãã㯠callback ãå®è¡ããŸããã代ããã«ãæ°ãã stack ã (æç€ºçã«ããããã¯withæã®çµããã«æé»çã«) close ããããšãã«å®è¡ãããŸããäŸãã°ãè€æ°ã®ãã¡ã€ã«ã "all or nothing" ã«éãåŠçãæ¬¡ã®ããã«æžããŸã:
with ExitStack() as stack: files = [stack.enter_context(open(fname)) for fname in filenames] # Hold onto the close method, but don't call it yet. close_files = stack.pop_all().close # If opening any file fails, all previously opened files will be # closed automatically. If all files are opened successfully, # they will remain open even after the with statement ends. # close_files() can then be invoked explicitly to close them all.
- close()¶
ããã«ã³ãŒã«ããã¯ã¹ã¿ãã¯ãå·»ãæ»ããã³ãŒã«ããã¯é¢æ°ãç»é²ã®éé ã«åŒã³åºããŸããç»é²ããããã¹ãŠã®ã³ã³ããã¹ããããŒãžã£ãŒãšçµäº callback ã«ãäŸå€ãèµ·ãããªãã£ãå Žåã®åŒæ°ãæž¡ãããŸãã
- class contextlib.AsyncExitStack¶
ExitStackã«äŒŒã éåæã³ã³ããã¹ããããŒãžã£ ã§ããã¹ã¿ãã¯äžã§åæãšéåæã®äž¡æ¹ã®ã³ã³ããã¹ããããŒãžã£ã®çµã¿åããããµããŒãããŸãããŸããåŸåŠçã®ããã®ã³ã«ãŒãã³ãæã£ãŠããŸããThe
close()method is not implemented;aclose()must be used instead.- async enter_async_context(cm)¶
Similar to
ExitStack.enter_context()but expects an asynchronous context manager.ããŒãžã§ã³ 3.11 ã§å€æŽ: cm ãéåæã³ã³ããã¹ããããŒãžã£ã§ãªãã£ãå Žåã
AttributeErrorã®ä»£ããã«TypeErroräŸå€ãéåºããŸãã
- push_async_exit(exit)¶
Similar to
ExitStack.push()but expects either an asynchronous context manager or a coroutine function.
- push_async_callback(callback, /, *args, **kwds)¶
Similar to
ExitStack.callback()but expects a coroutine function.
- async aclose()¶
Similar to
ExitStack.close()but properly handles awaitables.
Continuing the example for
@asynccontextmanager:async with AsyncExitStack() as stack: connections = [await stack.enter_async_context(get_connection()) for i in range(5)] # All opened connections will automatically be released at the end of # the async with statement, even if attempts to open a connection # later in the list raise an exception.
Added in version 3.7.
äŸãšã¬ã·ã¶
This section describes some examples and recipes for making effective use of
the tools provided by contextlib.
å¯å€æ°åã®ã³ã³ããã¹ããããŒãžã£ãŒããµããŒããã¶
ExitStack ã®ç¬¬äžã®ãŠãŒã¹ã±ãŒã¹ã¯ãã¯ã©ã¹ã®ããã¥ã¡ã³ãã«ããããŠããéããäžã€ã® with æã§å¯å€æ°åã®ã³ã³ããã¹ããããŒãžã£ãŒãä»ã®ã¯ãªãŒã³ã¢ãã颿°ããµããŒãããããšã§ãããŠãŒã¶ãŒã®å
¥å (æå®ãããè€æ°åã®ãã¡ã€ã«ãéãå Žåãªã©) ã«å¿ããŠè€æ°åã®ã³ã³ããã¹ããããŒãžã£ãŒãå¿
èŠãšãªãå Žåããããã€ãã®ã³ã³ããã¹ããããŒãžã£ãŒããªãã·ã§ã³ãšãªãå Žåã«ãå¯å€æ°åã®ã³ã³ããã¹ããããŒãžã£ãŒãå¿
èŠã«ãªããŸã:
with ExitStack() as stack:
for resource in resources:
stack.enter_context(resource)
if need_special_resource():
special = acquire_special_resource()
stack.callback(release_special_resource, special)
# Perform operations that use the acquired resources
äžã®äŸã«ããããã«ã ExitStack ã¯ã³ã³ããã¹ããããŒãžã£ãŒãããã³ã«ããµããŒãããŠããªããªãœãŒã¹ã®ç®¡çã with æã䜿ã£ãŠç°¡åã«è¡ããããã«ããŸãã
__enter__ ã¡ãœããããã®äŸå€ããã£ãããã¶
It is occasionally desirable to catch exceptions from an __enter__()
method implementation, without inadvertently catching exceptions from
the with statement body or the context manager's __exit__()
method. By using ExitStack the steps in the context management
protocol can be separated slightly in order to allow this:
stack = ExitStack()
try:
x = stack.enter_context(cm)
except Exception:
# handle __enter__ exception
else:
with stack:
# Handle normal case
å®éã®ãšããããã®ãããªã³ãŒããå¿
èŠã«ãªãã®ãªãã°ãå©çšããŠãã API åŽã§ try/except/finally æã䜿ã£ãçŽæ¥çãªãªãœãŒã¹ç®¡çã€ã³ã¿ãŒãã§ãŒã¹ãæäŸããã¹ãã§ãããããããã¹ãŠã® API ããã®ããã«ããèšèšãããŠãããšã¯éããŸãããããã³ã³ããã¹ããããŒãžã£ãŒãæäŸãããŠããå¯äžã®ãªãœãŒã¹ç®¡çAPIã§ãããªãã ExitStack ã䜿ã£ãŠ with æã䜿ã£ãŠåŠçããããšãã§ããªãæ§ã
ãªã·ãã¥ãšãŒã·ã§ã³ã®åŠçãããããšãã§ããŸãã
__enter__ å®è£
å
ã®ã¯ãªãŒã³ã¢ãã¶
As noted in the documentation of ExitStack.push(), this
method can be useful in cleaning up an already allocated resource if later
steps in the __enter__() implementation fail.
次ã®äŸã§ã¯ããªãœãŒã¹ã®ç¢ºä¿ãšéæŸã®é¢æ°ã«å ããŠããªãã·ã§ã³ã®ããªããŒã·ã§ã³é¢æ°ãåãåãã³ã³ããã¹ããããŒãžã£ãŒã§ããã®æ¹æ³ã䜿ã£ãŠã³ã³ããã¹ããããŒãžã£ãŒãããã³ã«ãæäŸããŠããŸã:
from contextlib import contextmanager, AbstractContextManager, ExitStack
class ResourceManager(AbstractContextManager):
def __init__(self, acquire_resource, release_resource, check_resource_ok=None):
self.acquire_resource = acquire_resource
self.release_resource = release_resource
if check_resource_ok is None:
def check_resource_ok(resource):
return True
self.check_resource_ok = check_resource_ok
@contextmanager
def _cleanup_on_error(self):
with ExitStack() as stack:
stack.push(self)
yield
# The validation check passed and didn't raise an exception
# Accordingly, we want to keep the resource, and pass it
# back to our caller
stack.pop_all()
def __enter__(self):
resource = self.acquire_resource()
with self._cleanup_on_error():
if not self.check_resource_ok(resource):
msg = "Failed validation for {!r}"
raise RuntimeError(msg.format(resource))
return resource
def __exit__(self, *exc_details):
# We don't need to duplicate any of our resource release logic
self.release_resource()
try-finally + flag 倿°ãã¿ãŒã³ã眮ãæãã¶
try-finally æã«ãfinally å¥ã®å
容ãå®è¡ãããã©ããã瀺ããã©ã°å€æ°ãçµã¿åããããã¿ãŒã³ãç®ã«ããããšããããããããŸãããäžçªã·ã³ãã«ãª (åã« except å¥ã䜿ãã ãã§ã¯åŠçã§ããªã) ã±ãŒã¹ã§ã¯æ¬¡ã®ãããªã³ãŒãã«ãªããŸã:
cleanup_needed = True
try:
result = perform_operation()
if result:
cleanup_needed = False
finally:
if cleanup_needed:
cleanup_resources()
try æã䜿ã£ãã³ãŒãã§ã¯ãã»ããã¢ãããšã¯ãªãŒã³ã¢ããã®ã³ãŒããä»»æã®é·ãã®ã³ãŒãã§åé¢ããŠããŸãã®ã§ãéçºè
ãã¬ãã¥ãŒã¢ã«ãšã£ãŠåé¡ã«ãªãããŸãã
ExitStack ã䜿ãã°ã代ããã« with æã®çµããã«å®è¡ãããã³ãŒã«ããã¯ãç»é²ããåŸã§ãã®ã³ãŒã«ããã¯ãã¹ããããããã©ãããæ±ºå®ã§ããŸã:
from contextlib import ExitStack
with ExitStack() as stack:
stack.callback(cleanup_resources)
result = perform_operation()
if result:
stack.pop_all()
This allows the intended cleanup behaviour to be made explicit up front, rather than requiring a separate flag variable.
ããããã¢ããªã±ãŒã·ã§ã³ããã®ãã¿ãŒã³ãå€çšããã®ã§ããã°ãå°ãããã«ããŒã¯ã©ã¹ãå°å ¥ããŠããã·ã³ãã«ã«ããããšãã§ããŸã:
from contextlib import ExitStack
class Callback(ExitStack):
def __init__(self, callback, /, *args, **kwds):
super().__init__()
self.callback(callback, *args, **kwds)
def cancel(self):
self.pop_all()
with Callback(cleanup_resources) as cb:
result = perform_operation()
if result:
cb.cancel()
ãããªãœãŒã¹ã®ã¯ãªãŒã³ã¢ãããåäœã®é¢æ°ã«ãŸãšãŸã£ãŠãªãå Žåã§ãã ExitStack.callback() ã®ãã³ã¬ãŒã¿ãŒåœ¢åŒãå©çšããŠãªãœãŒã¹éæŸåŠçã宣èšããããšãã§ããŸã:
from contextlib import ExitStack
with ExitStack() as stack:
@stack.callback
def cleanup_resources():
...
result = perform_operation()
if result:
stack.pop_all()
ãã³ã¬ãŒã¿ãŒãããã³ã«ã®äœ¿çšäžããã®ããã«å®£èšãããã³ãŒã«ããã¯é¢æ°ã¯åŒæ°ãåãããšãã§ããŸããããã®ä»£ããã«ããªãªãŒã¹ãããªãœãŒã¹ãã¯ããŒãžã£ãŒå€æ°ãšããŠã¢ã¯ã»ã¹ã§ããå¿ èŠããããŸãã
ã³ã³ããã¹ããããŒãžã£ãŒã颿°ãã³ã¬ãŒã¿ãŒãšããŠäœ¿ã¶
ContextDecorator ã¯ã³ã³ããã¹ããããŒãžã£ãŒãéåžžã® with æã«å ããŠé¢æ°ãã³ã¬ãŒã¿ãŒãšããŠãå©çšã§ããããã«ããŸãã
äŸãã°ã颿°ããŸãšãŸã£ãæããããã«å
¥ã£ãæãšåºãæã®æéããã©ãã¯ãããã¬ãŒã§ã©ãããããå ŽåããããŸãããã®ããã«é¢æ°ãã³ã¬ãŒã¿ãŒãšã³ã³ããã¹ããããŒãžã£ãŒãå¥ã
ã«æžã代ããã«ã ContextDecorator ãç¶æ¿ãããš1ã€ã®å®çŸ©ã§äž¡æ¹ã®æ©èœãæäŸã§ããŸã:
from contextlib import ContextDecorator
import logging
logging.basicConfig(level=logging.INFO)
class track_entry_and_exit(ContextDecorator):
def __init__(self, name):
self.name = name
def __enter__(self):
logging.info('Entering: %s', self.name)
def __exit__(self, exc_type, exc, exc_tb):
logging.info('Exiting: %s', self.name)
ãã®ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã¯ã³ã³ããã¹ããããŒãžã£ãŒãšããŠãå©çšã§ã:
with track_entry_and_exit('widget loader'):
print('Some time consuming activity goes here')
load_widget()
ãŸã颿°ãã³ã¬ãŒã¿ãŒãšããŠãå©çšã§ããŸã:
@track_entry_and_exit('widget loader')
def activity():
print('Some time consuming activity goes here')
load_widget()
Note that there is one additional limitation when using context managers
as function decorators: there's no way to access the return value of
__enter__(). If that value is needed, then it is still necessary to use
an explicit with statement.
åå䜿çšãåå©çšå¯èœãããã³ãªãšã³ãã©ã³ããªã³ã³ããã¹ããããŒãžã£Â¶
ã»ãšãã©ã®ã³ã³ããã¹ããããŒãžã£ã¯ã with æã®äžã§äžåºŠã ã䜿ããããããªå Žåã«å¹æçã«ãªãããã«æžãããŠããŸãããããåå䜿çšã®ã³ã³ããã¹ããããŒãžã£ã¯æ¯åæ°èŠã«çæãããªããã°ãªããŸãã - ããããåå©çšããããšãããšãäŸå€ãåŒãèµ·ããããæ£ããåäœããŸããã
ãã®å
±éã®å¶éãæå³ããããšã¯ãã³ã³ããã¹ããããŒãžã£ã¯ (äžèšãã¹ãŠã®äœ¿çšäŸã«ç€ºããšãã) äžè¬ã« with æã®ãããéšåã§çŽæ¥çæããããšãæšå¥šããããšããããšã§ãã
ãã¡ã€ã«ãªããžã§ã¯ãã¯åå䜿çšã®ã³ã³ããã¹ããããŒãžã£æå¹ã«å©çšããäŸã§ããæåã® with æã«ãããã¡ã€ã«ãã¯ããŒãºããããã以éãã®ãã¡ã€ã«ãªããžã§ã¯ãã«å¯Ÿãããã¹ãŠã® IO æäœã鲿¢ããŸãã
Context managers created using @contextmanager are also single use
context managers, and will complain about the underlying generator failing
to yield if an attempt is made to use them a second time:
>>> from contextlib import contextmanager
>>> @contextmanager
... def singleuse():
... print("Before")
... yield
... print("After")
...
>>> cm = singleuse()
>>> with cm:
... pass
...
Before
After
>>> with cm:
... pass
...
Traceback (most recent call last):
...
RuntimeError: generator didn't yield
ãªãšã³ãã©ã³ããªã³ã³ããã¹ããããŒãžã£Â¶
ããæŽç·Žãããã³ã³ããã¹ããããŒãžã£ã«ã¯"ãªãšã³ãã©ã³ã"ãªãã®ããããŸãããã®ãããªã³ã³ããã¹ããããŒãžã£ã¯ãè€æ°ã® with æã§äœ¿ããã ãã§ãªããåãã³ã³ããã¹ããããŒãžã£ããã§ã«äœ¿ã£ãŠãã with æã® å
éš ã§ã䜿ãããšãã§ããŸãã
threading.RLock ã¯ãªãšã³ãã©ã³ããªã³ã³ããã¹ããããŒãžã£ã®äŸã§ããããŸã suppress(), redirect_stdout(), ãã㊠chdir() ããªãšã³ãã©ã³ãã§ãã以äžã¯ãªãšã³ãã©ã³ããªå©çšæ³ã®éåžžã«åçŽãªäŸã§ã:
>>> from contextlib import redirect_stdout
>>> from io import StringIO
>>> stream = StringIO()
>>> write_to_stream = redirect_stdout(stream)
>>> with write_to_stream:
... print("This is written to the stream rather than stdout")
... with write_to_stream:
... print("This is also written to the stream")
...
>>> print("This is written directly to stdout")
This is written directly to stdout
>>> print(stream.getvalue())
This is written to the stream rather than stdout
This is also written to the stream
ãªãšã³ãã©ã³ããªæ§è³ªã®å®äŸã¯ãäºããåŒã³åºãããè€æ°ã®é¢æ°ãå«ãã§ããå¯èœæ§ãé«ãããããã£ãŠãã®äŸãããã¯ããã«è€éã§ãã
ãªãšã³ãã©ã³ãã§ããããšã¯ã¹ã¬ããã»ãŒãã§ããããšãšåã ã§ã¯ãªã ããšã«ã¯æ³šæãå¿
èŠã§ããããšãã° redirect_stdout() ã¯ã sys.stdout ãç°ãªãã¹ããªãŒã ã«æçžããããšã«ããã·ã¹ãã ã®ç¶æ
ã«å¯ŸããŠã°ããŒãã«ãªå€æŽãè¡ãããšãããæããã«ã¹ã¬ããã»ãŒãã§ã¯ãããŸããã
åå©çšå¯èœãªã³ã³ããã¹ããããŒãžã£Â¶
åå䜿çšã®ã³ã³ããã¹ããããŒãžã£ãšãªãšã³ãã©ã³ããªã³ã³ããã¹ããããŒãžã£ã®ããããšãç°ãªãã¿ã€ãã« "åå©çšå¯èœ" ãªã³ã³ããã¹ããããŒãžã£ããããŸã (ãããã¯ãããæç¢ºã«ã¯ã"åå©çšå¯èœã ããªãšã³ãã©ã³ãã§ãªã" ã³ã³ããã¹ããããŒãžã£ã§ãããªãšã³ãã©ã³ããªã³ã³ããã¹ããããŒãžã£ããŸãåå©çšå¯èœã ããã§ã)ãåå©çšå¯èœãªã³ã³ããã¹ããããŒãžã£ã¯è€æ°åå©çšããµããŒãããŸãããåãã³ã³ããã¹ããããŒãžã£ã®ã€ã³ã¹ã¿ã³ã¹ããã§ã« with æã§äœ¿ãããŠããå Žåã«ã¯å€±æããŸã (ãããã¯æ£ããåäœããŸãã)ã
threading.Lock ã¯åå©çšå¯èœã ããªãšã³ãã©ã³ãã§ãªãã³ã³ããã¹ããããŒãžã£ã®äŸã§ã (ãªãšã³ãã©ã³ããªããã¯ã®ããã«ã¯ threading.RLock ã代ããã«äœ¿ãå¿
èŠããããŸã)ã
åå©çšå¯èœã ããªãšã³ãã©ã³ãã§ãªãã³ã³ããã¹ããããŒãžã£ã®ããã²ãšã€ã®äŸã¯ ExitStack ã§ããããã¯çŸåšç»é²ãããŠãã å
šãŠã® ã³ãŒã«ããã¯é¢æ°ããã©ãã§ç»é²ããããã«ããããããåŒã³åºããŸã:
>>> from contextlib import ExitStack
>>> stack = ExitStack()
>>> with stack:
... stack.callback(print, "Callback: from first context")
... print("Leaving first context")
...
Leaving first context
Callback: from first context
>>> with stack:
... stack.callback(print, "Callback: from second context")
... print("Leaving second context")
...
Leaving second context
Callback: from second context
>>> with stack:
... stack.callback(print, "Callback: from outer context")
... with stack:
... stack.callback(print, "Callback: from inner context")
... print("Leaving inner context")
... print("Leaving outer context")
...
Leaving inner context
Callback: from inner context
Callback: from outer context
Leaving outer context
äŸã«ãããåºåã瀺ãããã«ãã²ãšã€ã®ã¹ã¿ãã¯ãªããžã§ã¯ããè€æ°ã® with æã§åå©çšããŠãæ£ããåäœããŸãããããå ¥ãåã«ããŠäœ¿ã£ãå Žåã¯ãäžçªå åŽã® with æãæããéã«ã¹ã¿ãã¯ã空ã«ãªããŸããããã¯æãŸããåäœãšã¯æããŸããã
ã²ãšã€ã® ExitStack ã€ã³ã¹ã¿ã³ã¹ãåå©çšãã代ããã«è€æ°ã®ã€ã³ã¹ã¿ã³ã¹ã䜿ãããšã«ããããã®åé¡ã¯åé¿ããããšãã§ããŸã:
>>> from contextlib import ExitStack
>>> with ExitStack() as outer_stack:
... outer_stack.callback(print, "Callback: from outer context")
... with ExitStack() as inner_stack:
... inner_stack.callback(print, "Callback: from inner context")
... print("Leaving inner context")
... print("Leaving outer context")
...
Leaving inner context
Callback: from inner context
Leaving outer context
Callback: from outer context