[Python-ideas] PEP 380 alternative: A yielding function
Guido van Rossum
guido at python.org
Tue Jul 27 20:01:12 CEST 2010
Have you really thought through the implementation in CPython? When a
non-generator function is called, there's usually a C stack frame in
the way which prevents yielding.
--Guido
On Tue, Jul 27, 2010 at 6:18 PM, Anders J. Munch <2010 at jmunch.dk> wrote:
> Looking at PEP 380 (http://www.python.org/dev/peps/pep-0380/), the
> need for yield forwarding syntax comes from the inability to delegate
> yielding functionality in the usual way. For example, if you have a
> recurring pattern including yields, like this (this is a toy example,
> please don't take it for more than that):
>
> if a:
> yield a
> if b:
> yield b
>
> you cannot do the extract function refactoring in the usual way:
>
> def yield_if_true(x):
> if x:
> yield x
> yield_if_true(a)
> yield_if_true(b)
>
> because yield_if_true would become a generator.
>
> PEP 380 addresses this by making the workaround - "for x in
> yield_if_true(a): yield x" - easier to write.
>
> But suppose you could address the source instead? Suppose you could
> write yield_if_true in such a way that it did not become a generator
> despite yielding?
>
> Syntactically this could be done with a yielding *function* in
> addition to the yield statement/expression, either as a builtin or a
> function in the sys module. Let's call it 'yield_' , for lack of a
> better name. The function would yield the nearest generator on the
> call stack.
>
> Now the example would work with a slight modifiction:
>
> def yield_if_true(x):
> if x:
> yield_(x)
> yield_if_true(a)
> yield_if_true(b)
>
> The real benefits from a yield_ function come with recursive
> functions. A recursive tree traversal that yields from the leaf nodes
> currently suffers from a performance penalty: Every yield is repeated
> as many times as the depth of the tree, turning a O(n) traversal
> algorithm into an O(n lg(n)) algorithm. PEP 380 does not change that.
>
> But a yield_ function could be O(1), regardless of the forwarding
> depth.
>
> To be fair, a clever implementation might be able to short-circuit a
> 'yield from' chain and achieve the same thing.
>
> Two main drawbacks of yield_:
> - Difficulty of implementation. Generators would need to keep an
> entire stack branch alive, instead of merely a single frame, and if
> that somehow affects the efficiency of simple generators, that would
> be bad.
> - 'the nearest generator on the call stack' is sort of a dynamic
> scoping thing, which has its problems. For example, if you forget
> to make the relevant function a generator (the "if 0: yield None"
> trick might have been needed but was forgotten), then the yield
> would trickle up to some random generator higher up, with confusing
> results. And if you use yield_ in a callback, well, let's just say
> that an interesting case too.
>
> All the same, if a yield_ function is practical, I think it is a
> better way to address the problems that motivate PEP 380. I'm guessing you
> could implement 'yield from' as a pure-Python
> function using yield_, making yield_ strictly more powerful, although
> I couldn't say for sure as I haven't studied the enhanced generator
> protocol.
>
> regards, Anders
>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> http://mail.python.org/mailman/listinfo/python-ideas
>
--
--Guido van Rossum (python.org/~guido)
More information about the Python-ideas
mailing list