Elaborate transaction() manager example (Chris A).

This commit is contained in:
Guido van Rossum 2014-11-28 17:26:33 -08:00
parent a6b3c8b1f7
commit 90addf57a2
1 changed files with 22 additions and 9 deletions

View File

@ -44,26 +44,39 @@ limitation, but notes that "use cases for these [are] rare to non-
existent". Unfortunately while intentional use is rare, it is easy to existent". Unfortunately while intentional use is rare, it is easy to
stumble on these cases by accident:: stumble on these cases by accident::
import contextlib
@contextlib.contextmanager @contextlib.contextmanager
def transaction(): def transaction():
begin() print('begin')
try: try:
yield from do_it() yield from do_it()
except: except:
rollback() print('rollback')
raise raise
else: else:
commit() print('commit')
def do_it(): def do_it():
initial_preparations() print('Refactored preparations')
yield yield # Body of with-statement is executed here
finishing_touches() print('Refactored finalization')
def gene():
for i in range(2):
with transaction():
yield i
# return
raise StopIteration # This is wrong
print('Should not be reached')
for i in gene():
print('main: i =', i)
Here factoring out ``do_it`` into a subgenerator has introduced a Here factoring out ``do_it`` into a subgenerator has introduced a
subtle bug: if the wrapped block raises ``StopIteration``, under the subtle bug: if the wrapped block raises ``StopIteration``, under the
current behavior ``do_it`` will fail but report success by returning current behavior this exception will be swallowed by the context
normally, causing the failed transaction to be committed! Similarly manager; and, worse, the finalization is silently skipped! Similarly
problematic behavior occurs when an ``asyncio`` coroutine raises problematic behavior occurs when an ``asyncio`` coroutine raises
``StopIteration``, causing it to terminate silently. ``StopIteration``, causing it to terminate silently.