The document discusses yield in Python and how it allows functions to act as generators by using the yield keyword instead of return, enabling generator functions to control execution by yielding values and resuming at the point after each yield. It explains how generators are created and how yield allows suspending and resuming execution of generator functions to implement features like coroutines, trampolines to avoid recursion limits, and the with statement in Python.
6. why thinking in yield?
@contextmanager
def transaction(conn):
class Job(object): trans = Job()
def __init__(self): conn.begin()
self._finished = False
try:
yield trans
def is_finished(self): except:
return self._finished conn.rollback()
raise
def finish(self): if trans.is_finished():
self._finished = True conn.commit()
else:
conn.rollback()
6
7. why thinking in yield?
with transaction(db) as trans:
if check_error1_happen(db):
return Response(“error1 happens”)
if check_error2_happen(db):
return Response(“error2 happens”)
db.table.update()
....
trans.finish()
return Response(“success”)
7
8. why thinking in yield?
main main
A yield function
B C
yield function
8
10. yield
Using a yield expression in a function definition is sufficient to
cause that definition to create a generator function instead of
a normal function.
10
11. yield
Using a yield expression in a function definition is sufficient to
cause that definition to create a generator function instead of
a normal function.
>>> def f():
... yield "hello world"
...
>>> type(f())
<type 'generator'>
10
13. yield
That generator then controls the execution of a generator
function.
• send()
• next() ==> send(None)
• throw()
• close() ==> throw(GeneratorExit)
11
14. yield
yield is a expression, not a statement. New in python 2.5
12
15. yield
yield is a expression, not a statement. New in python 2.5
>>> def f():
... a = yield "hello"
... print a
...
>>> b = f()
>>> b.send(None)
'hello'
>>> b.send("world")
world
StopIteration
12
68. “with_statement”
mgr = (EXPR)
exit = type(mgr).__exit__ # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
try:
VAR = value # Only if "as VAR" is present
BLOCK
except:
exc = False
if not exit(mgr, *sys.exc_info()):
raise
finally:
if exc:
exit(mgr, None, None, None)
43
69. “with_statement”
class Transaction(object):
def __init__(self, db):
self._db = db
self._trans = Job()
def __enter__(self):
self._db.begin()
return self._trans
def __exit__(self, type, value, traceback):
if type is not None:
self._db.rollback()
else:
self._db.commit()
yield transaction
44
73. python Trampoline
def f(n):
if n < 2:
return n
else:
return n + f(n - 1)
>>> f(999)
499500
>>> f(1000)
RuntimeError: maximum recursion depth exceeded
47
74. python Trampoline
sys.getrecursionlimit()
Return the current value of the recursion limit, the
maximum depth of the Python interpreter stack. This
limit prevents infinite recursion from causing an
overflow of the C stack and crashing Python. It can be
set by setrecursionlimit().
48
77. python Trampoline
• let generator "call" other generator by yielding
the generator they wish to invoke.
• Any non-generator value yielded by a
generator is returned to the generator that
"called" the one yielding the value.
51
79. python Trampoline
def trampoline(main):
stack = []
value = main
while True:
if type(value) is types.GeneratorType:
stack.append(value)
value = stack[-1].next()
else:
stack.pop()
if stack:
value = stack[-1].send(value)
else:
return value
53
86. Resources & References
• python references: yield expression
• python
• PEP 342: Coroutines via Enhanced Generators
• PEP 343: the with statement
58