@@ -32,6 +32,8 @@ def foo():
3232 yielded Effect will be passed back into the generator as the result of the
3333 ``yield`` expression. Yielded :func:`do_return` values will provide the
3434 ultimate result of the Effect that is returned by the decorated function.
35+ Note that :func:`do_return` is only necessary for Python 2 compatibility;
36+ return statements can be used directly in Python 3-only code.
3537
3638 It's important to note that any generator function decorated by ``@do``
3739 will no longer return a generator, but instead it will return an Effect,
@@ -78,6 +80,9 @@ def do_return(val):
7880 @do
7981 def foo():
8082 yield do_return('hello')
83+
84+ If you're writing Python 3-only code, you don't need to use this function,
85+ and can just use the `return` statement as normal.
8186 """
8287 return _ReturnSentinel (val )
8388
@@ -88,7 +93,7 @@ def _do(result, generator, is_error):
8893 val = generator .throw (* result )
8994 else :
9095 val = generator .send (result )
91- except StopIteration :
96+ except StopIteration as stop :
9297 # If the generator we're spinning directly raises StopIteration, we'll
9398 # treat it like returning None from the function. But there may be a
9499 # case where some other code is raising StopIteration up through this
@@ -98,7 +103,12 @@ def _do(result, generator, is_error):
98103 if tb .tb_next :
99104 raise
100105 else :
101- return None
106+ # Python 3 allows you to use `return val` in a generator, which
107+ # will be translated to a `StopIteration` with a `value` attribute
108+ # set to the return value. So we'll return that value as the
109+ # ultimate result of the effect. Python 2 doesn't have the 'value'
110+ # attribute of StopIteration, so we'll fall back to None.
111+ return getattr (stop , 'value' , None )
102112 if type (val ) is _ReturnSentinel :
103113 return val .result
104114 elif type (val ) is Effect :
0 commit comments