Функция Пустого Генератора Python


в python можно легко определить функцию итератора, поместив ключевое слово yield в тело функции, например:

def gen():
    for i in range(100):
        yield i

как я могу определить функцию генератора, которая не дает никакого значения (генерирует 0 значений), следующий код не работает, так как python не может знать, что он должен быть генератором, а не нормальной функцией:

def empty():
    pass

я мог бы сделать что-то вроде

def empty():
    if False:
        yield None

но это было бы очень некрасиво. Есть ли хороший способ реализовать пустую функцию итератора?

9 71

9 ответов:

можно использовать return один раз в генераторе; он останавливает итерацию, не давая ничего, и, таким образом, обеспечивает явную альтернативу тому, чтобы позволить функции выйти из области действия. Так что используйте yield чтобы превратить функцию в генератор, но предшествовать ему с return чтобы завершить генератор, прежде чем давать что-либо.

>>> def f():
...     return
...     yield
... 
>>> list(f())
[]

Я не уверен, что это намного лучше, чем то, что у вас есть-он просто заменяет no-op if заявление с no-op yield заявление. Но это больше идиоматический. Обратите внимание, что просто с помощью yield не работает.

>>> def f():
...     yield
... 
>>> list(f())
[None]

почему бы просто не использовать iter(())?

этот вопрос задает конкретно о пустом функции генератора. По этой причине я считаю, что это вопрос о внутренней согласованности синтаксиса Python, а не вопрос о лучшем способе создания пустого итератора в целом.

если вопрос на самом деле о лучшем способе создания пустого итератора, то вы можете согласен с Zectbumo о iter(()) вместо. Однако важно отметить, что iter(()) не возвращает функция! Он непосредственно возвращает пустой iterable. Предположим, вы работаете с API, который ожидает вызываемый that возвращает повторяемое. Вам придется сделать что-то вроде этого:

def empty():
    return iter(())

(кредит должен идти в Unutbu для предоставления первой правильной версии этого ответа.)

теперь, вы можете найти выше яснее, но я могу представить себе ситуации, в которых это было бы менее ясно. Рассмотрим этот пример длинного списка (надуманных) определений функций генератора:

def zeros():
    while True:
        yield 0

def ones():
    while True:
        yield 1

...

в конце этого длинного списка, я бы предпочел увидеть что-то с yield в нем, как это:

def empty():
    return
    yield

или, в Python 3.3 и выше (как было предложено DSM), это:

def empty():
    yield from ()

в присутствии yield ключевое слово дает понять, на какой взгляд, что это это просто еще одна функция генератора, точно так же, как и все остальные. Это займет немного больше времени, чтобы увидеть, что iter(()) версия делает то же самое.

это тонкая разница, но я честно думаю, что yieldфункций для более удобного и ремонтопригодны.

iter(())

не требуются генератор. Давайте, ребята!

Python 3.3 (потому что я на yield from удар, а потому @senderle украл мою первую мысль):

>>> def f():
...     yield from ()
... 
>>> list(f())
[]

но я должен признать, что мне трудно придумать прецедент для этого, для которого iter([]) или (x)range(0) не будет работать одинаково хорошо.

другой вариант:

(_ for _ in ())

Я предпочитаю следующее:

def foo():
  raise StopIteration()
  yield

"выход" превращает его в генератор, а исключение означает, что никто не включен в результат (чисто пустой результат).

должна быть функция генератора? Если нет, то как насчет

def f():
    return iter([])

"стандартным" способом создания пустого итератора является iter([]). Я предложил сделать [] аргумент по умолчанию для iter(); это было отклонено с хорошими аргументами, см. http://bugs.python.org/issue25215 - Jurjen

generator = (item for item in [])

для тех из вас, кто действительно нуждается в функции и на самом деле нужен генератор

empty = lambda: (_ for _ in ())