Как обесценить выход из синтаксиса в Python? - PullRequest
3 голосов
/ 24 сентября 2019

Теперь я изучаю различия между синтаксисом yield-from и await.Из официальной документации по python генератор yield-from generator () - это просто синтаксический suger следующего кода:

for i in generator(): yield i

Но я не могу отменить вывод yield-from в приведенном ниже примере.

def accumlate():
    # context
    accumlator = 0
    while True:
        next = yield
        if next is None:
            return accumlator
        accumlator += next


def gather(tallies):
    while True:
        tally = yield from accumlate() # (*)
        tallies.append(tally)

def main():
    tallies = []
    accumlator = gather(tallies)
    next(accumlator)
    for i in range(4):
        accumlator.send(i)

    accumlator.send(None)
    for i in range(6, 10):
        accumlator.send(i)
    accumlator.send(None)
    print(tallies)

if __name__ == "__main__":
    main()

Я пытался просто заменить yield-from версией for-in, но это не сработало, потому что for-in нельзя разместить справа от переменной tally.Что такое точный десугар кода, отмеченного звездочкой?

Ответы [ 2 ]

0 голосов
/ 24 сентября 2019

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

Выдержка из документации StopIteration:

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

Следовательно, вам нужно всего лишь "десагировать" функцию gather кактакие:

def gather(tallies):
    while True:
        a = accumlate()
        a.send(None)
        while True:
            try:
                a.send((yield))
            except StopIteration as e:
                tallies.append(e.value)
                break
0 голосов
/ 24 сентября 2019

result = yield from generator() не легко заменить, это способ получения возвращаемого значения генератора

см. https://www.python.org/dev/peps/pep-0380/#proposal

, чтобы имитировать немного происходящегобез использования yield from мы должны изменить оба генератора

def accumlate():
    # context
    accumlator = 0
    while True:
        next = yield
        if next is None:
            raise StopIteration(accumlator)
        accumlator += next


def gather(tallies):
    internal_acc = accumlate()
    internal_acc.send(None)
    while True:
        try:
            number_to_add = yield
            internal_acc.send(number_to_add)
        except StopIteration as e:
            internal_acc = accumlate()
            internal_acc.send(None)
            tallies.append(e.value)

accumlate больше не возвращается, но повышается и gather должна пытаться, кроме этого повышения,

после internal_acc исчерпан, новый создается в исключении

есть что-то большее, как видно в pep0380, но в основном возвращение генератора - это повышение, а выход из - это компактный улов для этого

...