Fix two examples that were broken by the new semantics.
This commit is contained in:
parent
a0a335673a
commit
1b6c373966
124
pep-0343.txt
124
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
|
||||
|
||||
|
|
Loading…
Reference in New Issue