Rename @with_template and class Wrapper to @contextmanager and class
ContextManager. Mark open issues as resolved.
This commit is contained in:
parent
050ac22ecc
commit
f2d367de26
46
pep-0343.txt
46
pep-0343.txt
|
@ -111,7 +111,7 @@ Motivation and Summary
|
|||
example, it was impossible to do this for the opening example.
|
||||
The idea was to define the template like this:
|
||||
|
||||
@with_template
|
||||
@contextmanager
|
||||
def opening(filename):
|
||||
f = open(filename)
|
||||
try:
|
||||
|
@ -258,7 +258,7 @@ Generator Decorator
|
|||
that makes it possible to use a generator that yields exactly once
|
||||
to control a with-statement. Here's a sketch of such a decorator:
|
||||
|
||||
class Wrapper(object):
|
||||
class ContextManager(object):
|
||||
|
||||
def __init__(self, gen):
|
||||
self.gen = gen
|
||||
|
@ -285,16 +285,16 @@ Generator Decorator
|
|||
else:
|
||||
raise RuntimeError("generator caught exception")
|
||||
|
||||
def with_template(func):
|
||||
def contextmanager(func):
|
||||
def helper(*args, **kwds):
|
||||
return Wrapper(func(*args, **kwds))
|
||||
return ContextManager(func(*args, **kwds))
|
||||
return helper
|
||||
|
||||
This decorator could be used as follows:
|
||||
|
||||
@with_template
|
||||
@contextmanager
|
||||
def opening(filename):
|
||||
f = open(filename) # IOError here is untouched by Wrapper
|
||||
f = open(filename) # IOError is untouched by ContextManager
|
||||
try:
|
||||
yield f
|
||||
finally:
|
||||
|
@ -332,18 +332,20 @@ Optional Extensions
|
|||
is entered).
|
||||
|
||||
OTOH such mistakes are easily diagnosed; for example, the
|
||||
with_template decorator above raises RuntimeError when the second
|
||||
contextmanager decorator above raises RuntimeError when the second
|
||||
with-statement calls f.__enter__() again.
|
||||
|
||||
Open Issues
|
||||
Resolved Open Issues
|
||||
|
||||
Discussion on python-dev has revealed some open issues. I list
|
||||
them here, with my preferred resolution and its motivation. The
|
||||
PEP as currently written reflects this preferred resolution.
|
||||
Discussion on python-dev revealed some open issues. I list them
|
||||
here, with my preferred resolution and its motivation. The PEP
|
||||
has been accepted without these being challenged, so the issues
|
||||
are now resolved.
|
||||
|
||||
1. The __exit__() method of the with_template decorator class catches
|
||||
StopIteration and considers it equivalent to re-raising the exception
|
||||
passed to throw(). Is allowing StopIteration right here?
|
||||
1. The __exit__() method of the contextmanager decorator class
|
||||
catches StopIteration and considers it equivalent to re-raising
|
||||
the exception passed to throw(). Is allowing StopIteration
|
||||
right here?
|
||||
|
||||
This is so that a generator doing cleanup depending on the
|
||||
exception thrown (like the transactional() example below) can
|
||||
|
@ -368,7 +370,7 @@ Examples
|
|||
1. A template for ensuring that a lock, acquired at the start of a
|
||||
block, is released when the block is left:
|
||||
|
||||
@with_template
|
||||
@contextmanager
|
||||
def locking(lock):
|
||||
lock.acquire()
|
||||
try:
|
||||
|
@ -390,7 +392,7 @@ Examples
|
|||
2. A template for opening a file that ensures the file is closed
|
||||
when the block is left:
|
||||
|
||||
@with_template
|
||||
@contextmanager
|
||||
def opening(filename, mode="r"):
|
||||
f = open(filename, mode)
|
||||
try:
|
||||
|
@ -407,7 +409,7 @@ Examples
|
|||
3. A template for committing or rolling back a database
|
||||
transaction:
|
||||
|
||||
@with_template
|
||||
@contextmanager
|
||||
def transactional(db):
|
||||
db.begin()
|
||||
try:
|
||||
|
@ -433,7 +435,7 @@ Examples
|
|||
|
||||
5. Redirect stdout temporarily:
|
||||
|
||||
@with_template
|
||||
@contextmanager
|
||||
def redirecting_stdout(new_stdout):
|
||||
save_stdout = sys.stdout
|
||||
sys.stdout = new_stdout
|
||||
|
@ -454,7 +456,7 @@ Examples
|
|||
|
||||
6. A variant on opening() that also returns an error condition:
|
||||
|
||||
@with_template
|
||||
@contextmanager
|
||||
def opening_w_error(filename, mode="r"):
|
||||
try:
|
||||
f = open(filename, mode)
|
||||
|
@ -491,7 +493,7 @@ Examples
|
|||
|
||||
import decimal
|
||||
|
||||
@with_template
|
||||
@contextmanager
|
||||
def extra_precision(places=2):
|
||||
c = decimal.getcontext()
|
||||
saved_prec = c.prec
|
||||
|
@ -520,7 +522,7 @@ Examples
|
|||
|
||||
9. Here's a more general Decimal-context-switching template:
|
||||
|
||||
@with_template
|
||||
@contextmanager
|
||||
def decimal_context(newctx=None):
|
||||
oldctx = decimal.getcontext()
|
||||
if newctx is None:
|
||||
|
@ -545,7 +547,7 @@ Examples
|
|||
|
||||
10. A generic "object-closing" template:
|
||||
|
||||
@with_template
|
||||
@contextmanager
|
||||
def closing(obj):
|
||||
try:
|
||||
yield obj
|
||||
|
|
Loading…
Reference in New Issue