

The Python yield keyword explained - interro
http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained

======
akashshah
Other amazing Python answers by the same guy:

What is a metaclass in Python -
[http://stackoverflow.com/questions/100003/what-is-a-
metaclas...](http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-
python/6581949#6581949)

Understanding Python decorators -
[http://stackoverflow.com/questions/739654/understanding-
pyth...](http://stackoverflow.com/questions/739654/understanding-python-
decorators/1594484#1594484)

------
kevsamuel
Hi guys, I'm the autor of the answers.

Thanks for the feedback. Because of comments like these, I decided to spend
more time at training people for a living, and I'm loving it.

So don't underestimate the power of web comments, it can literally change the
way people live.

~~~
emmelaich
Great stuff. I do like to see the simplest possible exposition of any
idea/technique though; here's my attempt at a simplest possible.

    
    
        def y():
            yield 1
    	yield 2
    
        for i in y():
            print i

~~~
kevsamuel
You got it.

------
ars
A helpful hint on the name: Yield should be read like "Yields" as in "returns"
or "produces".

Not Yield as in the common multithreading command to allow another thread to
run.

PS. Anyone know why they chose such a confusing name?

~~~
Someone
Because it allows another thread to run. Yes, they actually are coroutines,
but that is an implementation detail. Just look at it as an optimization for
the case where at most one of the two threads (the one producing the values
and the one consuming it) runs at a time.

------
jiggy2011
What I find weird about the yield keyword is that it seems to effect the
execution of code that comes before the statement, causing it not to execute
until later.

For example:

    
    
      def createGenerator():
         print "aaa"
    
      mygen = createGenerator()
    

outputs:

 _aaa_

Whereas

    
    
      def createGenerator():
        print "aaa"
        yield
    
      mygen = createGenerator()
    

Outputs nothing.

~~~
gejjaxxita
The presence of the yield keyword in a function definition means the function
will return a generator when it's called. Therefore "print "aaa"" is not
executed on "mygen = createGenerator()" as expected. "print "aaa"" is infact
executed when mygen.next() is called.

To emphasise this point, it is the _existence_ of the yield keyword which
causes the function to return a generator when it is called - it will not
execute any of the code. This is why the following results in an error:

    
    
      >>> def hello(j):
      ...     if j>2:
      ...         return "big number"
      ...     elif j<2:
      ...         yield "small number"
    

A return keyword cannot exist within the body of a generator - it makes no
sense.

A more detailed explanation can be found here
<http://docs.python.org/2.5/ref/yieldexpr.html>

~~~
jiggy2011
I think I mostly understand the idea, the presence of the yield statement
transforms the nature of the parent function itself and makes evaluation lazy.

This seems a little weird syntactically though because it feels like the
interpreter is somehow reading ahead in the program. It also means you don't
necessarily know that this is a lazy function unless you read to the end.

A more intuitive syntax might be something like:

    
    
      def lazy createGenerator():
        print "aaa"
        yield "bbb"

~~~
csense
This syntax would against the Python principle DRY (Don't Repeat Yourself):
The "lazy" keyword conveys no information that doesn't exist in the function
body.

Also, Python has precedent for this scanning behavior. One of the fundamental
features of Python is that the scope of a variable is determined by the
presence of an assignment statement in a function. For example:

    
    
      a = 1
      def f():
         print a      # UnboundLocalError occurs here
         a = 2
      f()
    

If you know Javascript, think about how often you need to use the "var"
keyword in that language, and how easy it is to accidentally pollute the
global namespace by omitting it.

~~~
gejjaxxita
This is an insightful point. I tend to regard this scanning behaviour as a
"quirk" rather than something fitting in more with some deeper Python
philosophy.

A specific syntax for generators would in my view be generally superior,
containing the same number of new keywords (generator now replacing yield) and
providing enhanced clarity.

    
    
      generator hello(n):
         for i in range(n):
             return i
    

I am generally neutral about variable scope being determined by the assignment
of a statement in a function - in 99.99% of cases the intuitive thing happens.

~~~
eurleif
Except you can use `return` without argument to return early from a generator,
and `yield` without argument yields None, so they need to be separate
keywords.

~~~
gejjaxxita
This functionality is so arcane that it's not needed.

~~~
eurleif
Early return is definitely needed. I guess you could make bare `return` early
return, and `return None` the way to yield None, but that's kind of confusing.

~~~
gejjaxxita
I agree that would be confusing, but I question that early return is needed -
I don't think I've ever seen a generator example where early return is used.
It could be that it's because I haven't seen enough examples of course. Please
share some examples of a generator with early return which can't be
accomplished easily and clearly in some other way.

~~~
eurleif

        def first10(*iterables):
            n = 0
            for iterable in iterables:
                for item in iterable:
                    yield item
                    n += 1
                    if n == 10:
                        return

~~~
csense
This is actually a one-liner, because itertools is awesome:

    
    
      first10 = lambda iterables : itertools.islice(itertools.chain(*iterables), 0, 10)

------
johnsonqq
It's a coroutine. Not exactly revolutionary.

~~~
bthomas
I use yield and generators regularly. They just make sense, but I never knew
what a coroutine is in an academic sense

~~~
johnsonqq
This is why you study CS at university before you start work as a programmer.
Otherwise you end up being amazed by the basic CS concepts, or worse, you end
up reinventing them badly.

~~~
kmfrk
Does studying CS at university make people as insufferably grumpy and
unhelpful as you?

~~~
johnsonqq
Come on, I've got a reasonable point here. People post on forums asking these
questions which should have been answered during their educations.

If civil engineers had a forum site and someone asked "how do I calculate the
load a simple beam", people would say, what the fuck are you doing in your job
if you don't know that? Who is employing you and why? Where did you go to
college? Who was your tutor because next time I'm at a dinner at my college
I'm going to ask him how the fuck did they pass you.

Our current trend of saying college doesn't matter really starts to be a
problem when professional programmers (yeah I'm assuming that the guy in the
question is) are asking basic questions like this. This shows that we do need
college education for programmers.

It also irritates me - this guy could have taken the time to learn all these
basics, but for whatever reason he thought it didn't matter, and now he's
paying for it.

~~~
monkeyfacebag
Neither a college education nor continued employment in the field is a
requirement to ask a stackoverflow question. In fact, I'd venture to say that
a version of stackoverflow where the default answer to everything was "you
should have learned this in college" would not be very useful (or used) at
all. If you find the discussion beneath you, I suggest that you not
participate and find a better use of your time. Others may be getting value
from it and I can't for the life of me understand why you think this is a bad
thing.

