Является ли генератор вызываемым? Какой генератор?

Генератор - это просто функция, которая возвращает объект, по которому вы можете вызвать следующий, так что для каждого вызова оно возвращает некоторое значение, пока оно не вызывает исключение StopIteration, сигнализируя, что все значения были сгенерированы. Такой объект называется итератором.

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

Я процитировал это из Понимание генераторов в Python?

Вот что я пытаюсь выяснить:

  • Каков генератор? myGen или myGen(6)?

    Согласно цитированной выше цитате, я думаю, что генератор должен быть myGen. И myGen(6) - это возвращаемый объект итератора. Но я действительно не уверен в этом.

  • Когда я попробовал это:

    >>> 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     
    

Итак, согласно <1> и <2>, g type является "генератором", и он не может быть вызван. Но генераторы вызываются, а вызов генератора получает объект-итератор Что здесь происходит?

Когда я искал ответы, я сталкивался с Каждый раз, когда вы определяете функцию, python создает вызываемый объект.

Итак, могу ли я сказать что-то вроде этого? когда определена функция myGen, myGen - это имя, относящееся к вызываемому объекту, который является экземпляром класса, который имеет метод __call__. В этом случае myGen является генератором, а myGen(6) является возвращенным итератором при вызове myGen.

Но почему type(g) возвращает <type 'generator'> вообще? И эта возвращаемая вещь iterator также выглядит подозрительной для меня, поскольку в этой функции нет инструкции return.

Не то, чтобы функции всегда возвращали что-то (по крайней мере None, когда во время выполнения не было достигнуто выражение return), а конец функции достигнут)?

Ответ 1

Терминология, к сожалению, сбивает с толку, поскольку "генератор" обычно используется для обозначения функции или возвращенного итератора, что трудно сказать, что одно использование является более правильным. В документации отчета о выходе говорится

Оператор yield используется только при определении функции генератора, и используется только в теле функции генератора. Использование урожая в определении функции достаточно, чтобы определение для создания функции генератора вместо нормального функция.

Когда вызывается функция генератора, она возвращает итератор, известный как итератор генератора, или чаще, генератор .

оригинальный PEP, представляющий концепцию, говорит

Обратите внимание, что когда намерение ясно из контекста, неквалифицированное имя "генератор" может использоваться для обозначения либо функции генератора, либо Генератор-итератор.

Если вы хотите сделать четкое различие, используйте "функцию генератора" для функции и "итератор генератора" для итератора.

Ответ 2

1) myGen - это функция, которая при вызове возвращает объект-генератор, поэтому да, myGen(6) является объектом-генератором.

2) Генераторы поставляют __iter__ и next(): docs