Question

A generator is simply a function which returns an object on which you can call next, such that for every call it returns some value, until it raises a StopIteration exception, signaling that all values have been generated. Such an object is called an iterator.

>>> def myGen(n):
...     yield n
...     yield n + 1
... 
>>> g = myGen(6)

I quoted this from Understanding Generators in Python?

Here is what I am trying to figure out:

  1. Which is the generator? myGen or myGen(6)?

    According to the quote mentioned above, I think the generator should be myGen. And myGen(6) is the returned iterator object. But I am really not sure about it.

  2. When I tried this:

    >>> type(myGen)
    <type 'function'>
    >>> type(g)         # <1>this is confusing me.
    <type 'generator'>  
    >>> callable(g)     # <2> g is not callable.  
    False               
    >>> callable(myGen)
    True
    >>> g is iter(g)    # <3> so g should an iterable and an iterator 
    True                # at the same time. And it will be passed as an argument
    >>> for i in g:     # to built-in function `next()` in a "for...in..." loop.
            print i     # (is that correct?)
    
    6
    7     
    

So, according to <1> and <2>, g's type is 'generator' and it is not callable. But generators are callable, and calling a generator gets you an iterator object What's going on here?

When I was searching for answers, I run into Every time you define a function python creates a callable object.

So, can I say something like this? when the function myGen is defined, myGen is a name referring to a callable object which is an instance of a class that has a __call__ method. In this case, myGen is a generator, and myGen(6) is the returned iterator when myGen is called.

But why does type(g) return <type 'generator'> at all? And this returned iterator thing also looks suspicious to me since there is no return statement in the function.

Isn't it that Functions always return something (at least None, when no return-statement was reached during execution and the end of the function is reached)?

Was it helpful?

Solution

The terminology is unfortunately confusing, as "generator" is so commonly used to refer to either the function or the returned iterator that it's hard to say one usage is more correct. The documentation of the yield statement says

The yield statement is only used when defining a generator function, and is only used in the body of the generator function. Using a yield statement in a function definition is sufficient to cause that definition to create a generator function instead of a normal function.

When a generator function is called, it returns an iterator known as a generator iterator, or more commonly, a generator.

The original PEP introducing the concept says

Note that when the intent is clear from context, the unqualified name "generator" may be used to refer either to a generator-function or a generator-iterator.

If you want to make a clear distinction, use "generator function" for the function and "generator iterator" for the iterator.

OTHER TIPS

1) myGen is function which when invoked returns a generator object - so yes, myGen(6) is a generator object.

2) Generators supply __iter__ and next(): docs

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top