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, ...)