From 1b6c373966e8ab08511dba6c383565fc87da2fcd Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 28 Feb 2006 22:49:15 +0000 Subject: [PATCH] Fix two examples that were broken by the new semantics. --- pep-0343.txt | 124 ++++++++++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 65 deletions(-) diff --git a/pep-0343.txt b/pep-0343.txt index 018c1c529..f95e46579 100644 --- a/pep-0343.txt +++ b/pep-0343.txt @@ -576,7 +576,7 @@ Examples The tense used in the names of the example context managers is not arbitrary. Past tense ("-ed") is used when the name refers to an action which is done in the __enter__ method and undone in the - __exit__ method. Progressive tense ("-ing") is used when the name + __exit__ method. Progressive tense ("-ing") is used when the name refers to an action which is to be done in the __exit__ method. 1. A template for ensuring that a lock, acquired at the start of a @@ -643,6 +643,8 @@ Examples self.lock.acquire() def __exit__(self, type, value, tb): self.lock.release() + if type is not None: + raise type, value, tb (This example is easily modified to implement the other relatively stateless examples; it shows that it is easy to avoid @@ -769,34 +771,35 @@ Examples # General Decimal Arithmetic Specification return +s # Convert result to normal context - 10. A generic "object-closing" template: + 10. A generic "object-closing" template: - @contextmanager - def closing(obj): - try: - yield obj - finally: - try: - close = obj.close - except AttributeError: - pass - else: - close() + @contextmanager + def closing(obj): + try: + yield obj + finally: + try: + close = obj.close + except AttributeError: + pass + else: + close() - This can be used to deterministically close anything with a - close method, be it file, generator, or something else. It can - even be used when the object isn't guaranteed to require - closing (e.g., a function that accepts an arbitrary iterable): + This can be used to deterministically close anything with a + close method, be it file, generator, or something else. It + can even be used when the object isn't guaranteed to require + closing (e.g., a function that accepts an arbitrary + iterable): - # emulate opening(): - with closing(open("argument.txt")) as contradiction: - for line in contradiction: - print line + # emulate opening(): + with closing(open("argument.txt")) as contradiction: + for line in contradiction: + print line - # deterministically finalize an iterator: - with closing(iter(data_source)) as data: - for datum in data: - process(datum) + # deterministically finalize an iterator: + with closing(iter(data_source)) as data: + for datum in data: + process(datum) 11. Native contexts for objects with acquire/release methods: @@ -807,7 +810,7 @@ Examples def released(self): return unlocked(self) - Sample usage: + Sample usage: with my_lock: # Operations with the lock held @@ -820,54 +823,43 @@ Examples supplied contexts from left-to-right to avoid excessive indentation: - class nested(object): - def __init__(self, *contexts): - self.contexts = contexts - self.entered = None - - def __context__(self): - return self - - def __enter__(self): - if self.entered is not None: - raise RuntimeError("Context is not reentrant") - self.entered = deque() - vars = [] + @contextmanager + def nested(*contexts): + exits = [] + vars = [] + exc = (None, None, None) + try: try: - for context in self.contexts: + for context in contexts: mgr = context.__context__() - vars.append(mgr.__enter__()) - self.entered.appendleft(mgr) + exit = mgr.__exit__ + enter = mgr.__enter__ + vars.append(enter()) + exits.append(exit) + yield vars except: - self.__exit__(*sys.exc_info()) - raise - return vars - - def __exit__(self, *exc_info): - # Behave like nested with statements - # first in, last out - # New exceptions override old ones - ex = exc_info - for mgr in self.entered: + exc = sys.exc_info() + finally: + while exits: + exit = exits.pop() try: - mgr.__exit__(*ex) + exit(*exc) except: - ex = sys.exc_info() - self.entered = None - if ex is not exc_info: - raise ex[0], ex[1], ex[2] + exc = sys.exc_info() + if exc != (None, None, None): + raise - Sample usage: + Sample usage: - with nested(a, b, c) as (x, y, z): - # Perform operation + with nested(a, b, c) as (x, y, z): + # Perform operation - Is equivalent to: + Is equivalent to: - with a as x: - with b as y: - with c as z: - # Perform operation + with a as x: + with b as y: + with c as z: + # Perform operation Reference Implementation @@ -911,6 +903,8 @@ References [12] http://sourceforge.net/tracker/index.php?func=detail&aid=1223381&group_id=5470&atid=305470 + [13] + http://mail.python.org/pipermail/python-dev/2006-February/061903.html Copyright