[Python-ideas] with None (Was: Re: Enhanced context managers with ContextManagerExit and None)

Serhiy Storchaka storchaka at gmail.com
Tue Aug 13 16:48:22 CEST 2013


07.08.13 17:23, Kristján Valur Jónsson написав(ла):
> 2) The mechanism used in implementing ContextManagerExit above is easily extended to allowing a special context manager: None.  This is useful for having _optional_ context managers.  E.g. code like this:
>      with performance_timer():
>          do_work()
>
>      def performance_timer():
>          if profiling:
>              return accumulator
>          return None
>
> None becomes the trivial context manager and its __enter__ and __exit__ calls are skipped, along with their overhead.

+1 to this idea. Of course ExitStack is powerful tool but it is too 
verbose for many simple cases.

Consider simple example:

     file = open(...) if ... else None
     file2 = open(...) if ... else None
     process(file, file2, ...)
     if file is not None:
         file.close()
     if file2 is not None:
         file2.close()

This code is not exception-safe. There are some ways to write it right.

1. With try/finally and a check in finally block:

     file = open(...) if ... else None
     try:
         file2 = open(...) if ... else None
         try:
             process(file, file2, ...)
         finally:
             if file2 is not None:
                 file2.close()
     finally:
         if file is not None:
             file.close()

2. With a code duplication (note that process can be not a one-line call 
of a function):

     if ...:
         with open(...) as file:
             if ...:
                 with open(...) as file2:
                     process(file, file2, ...)
             else:
                 process(file, None, ...)
     else:
         if ...:
             with open(...) as file2:
                 process(None, file2, ...)
         else:
             process(None, None, ...)

3. With ExitStack:

     import contextlib
     with contextlib.ExitStack() as cm:
         if ...:
             file = open(...)
             cm.enter_context(file)
         else:
             file = None
         if ...:
             file2 = open(...)
             cm.enter_context(file2)
         else:
             file2 = None
         process(file, file2, ...)

And when the with statement will support None as a "null-manager":

     file = open(...) if ... else None
     with file:
         file2 = open(...) if ... else None
         with file2:
             process(file, file2, ...)




More information about the Python-ideas mailing list