Эквивалент `return` для генераторов Python

Иногда при переписывании рекурсивных функций в качестве генераторов я упускаю краткость return,

"""
Returns a list of all length n strings that can be made out of a's and/or b's.
"""
def ab_star(n):
    if n == 0:
        return [""]

    results = []
    for s in ab_star(n - 1):
        results.append("a" + s)
        results.append("b" + s)

    return results

превращается в

"""
Generator for all length n strings that can be made out of a's and/or b's.
"""
def ab_star(n):
    if n == 0:
        yield ""

    else:
        for s in ab_star(n - 1):
            yield "a" + s
            yield "b" + s

Это то else это меня раздражает. Хотелось бы, чтобы был способ сказать "yield, и это все, так что выход из функции ". Есть ли способ?

2 ответа

Решение

Не пропустите return, используй это.

Вы можете return сразу после тебя yield,

def ab_star(n):
    if n == 0:
        yield ""
        return
    for s in ab_star(n - 1):
        yield "a" + s
        yield "b" + s

Альтернативой является использование return в обоих случаях, когда первый случай возвращает последовательность длиной 1, а второй возвращает выражение-генератор:

def ab_star(n):
    if n == 0:
        return ( "", )
    return ( c+s for s in ab_star(n - 1) for c in 'ab' )

Это избегание yield избегает ограничения, что вы не можете использовать оба return <value> а также yield в той же функции.

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

Нет Когда я писал "Простые генераторы PEP", я заметил:

Q. Then why not allow an expression on "return" too?

A. Perhaps we will someday.  In Icon, "return expr" means both "I'm
   done", and "but I have one final useful value to return too, and
   this is it".  At the start, and in the absence of compelling uses
   for "return expr", it's simply cleaner to use "yield" exclusively
   for delivering values.

Но это никогда не получало тяги. Пока это не происходит;-), вы можете сделать ваш генератор более похожим на вашу первую функцию, написав первую часть как:

if n == 0:
    yield ""
    return

Тогда вы можете бросить else: Заявление и отступление от всего остального.

Другие вопросы по тегам