question about generators

Andrew Koenig ark at research.att.com
Thu Aug 15 13:30:37 EDT 2002


Aha!  I just realized part of the origin of my puzzlement.

Yield actually does one of two very different things depending
on context.  Consider:

        def f():
                yield 1
                yield 2

The "yield 1" statement does two things:

        1) It creates a generator object and returns that object to
           the caller;

        2) When the caller calls the generator's "next" method,
           it passes 1 back to the caller.

The "yield 2" statement does only one thing: It passes 2 back to the
caller.

Let's call these two statements "type 1" and "type 2" yield
statements.

How do we know which yield statement does what?  The first statement
executed in a function is type 1, all others, including re-executions
of that same statement, are type 2.

If a function calls another function that also contains a yield
statement, the first yield statement executed in that function is
also type 1.

There is no way of executing a type 2 yield statement in a function
without first executing a type 1 yield statement in the same function.

These facts mean that yield statements break a form of abstraction
that is commonplace in many other contexts: the ability to take a
collection of statements and put them in a function.  For example:

        def f():
                <statement 1>
                <statement 2>
                <statement 3>
                <statement 4>

Under ordinary circumstances, I can rewrite this as

        def f():
                <statement 1>
                g()
                <statement 4>

        def g():
                <statement 2>
                <statement 3>

without changing the meaning of the program (provided that statement 2
and statement 3 do not refer to local variables of f).

However, if I use yield statements, the abstraction breaks down:

        def f():
                yield 1
                yield 2
                yield 3
                yield 4

is not equivalent to

        def f():
                yield 1
                g()
                yield 4

        def g():
                yield 2
                yield 3

I think that Tim's "yield every g()" notion is really a way of saying
``I want to call g, but I want every yield in g and anything it calls
to be considered type 2, not type 1.''

-- 
Andrew Koenig, ark at research.att.com, http://www.research.att.com/info/ark



More information about the Python-list mailing list