Каково функционирование yield в Пайтоне

Я хочу узнать, каково функционирование размещенного слова yield в Пайтоне, и в каких случаях возможно применяться.

Например, если у меня есть следующий код:

def contador(max):
    n=0
    while n < max:
            yield n
            n=n+1

Какую функцию он выполняет yield там, так как в функции я приучен видеть стоимость возврата со словом return.

8
задан 20.03.2016, 22:51
3 ответа

Изданный (у предыдущей версии были ошибки концепции)

Пример нам показался первым:

def contador(max):
    n=0
    while n < max:
            yield n
            n=n+1

mycont = contador(5)

for i in mycont:
    print(i)

# print(mycont)

Результат скроллирования предыдущего

0
1
2
3
4

Результат - тот же самый, что если, вместо mycont = contador(5) был instanciado список: mycont = [0,1,2,3,4] или mycont = range(0,5). Но в самом деле то, что происходит, очень различное.

Когда переводчик Пайтон находит функцию, которая включает один yield (или некоторые), пойми, что, назвав эту функцию, мы не получим стоимость, возвращенную с одним return, но мы получим генератор (generator).

Генератор ведет себя похоже на список, в чувстве, которое может пробежаться iterador - различие состоит в том, что стоимость хранится в коллекции, но они производятся "on the fly". Генератор также могут instanciar с выражением между скобкой, как

>>> migen= (x**2 for x in range(1,5))
>>> for i in migen:
>>>     print (i)
1
4
9
16

... но альтернатива с yield он более гибкий (хотя что-то более тяжелое усваивания).

В начальном примере, в ассигновании мы имеем в mycont генератор - тело функции contador() он все еще не прокрутил изображение в окне. Будучи использован в повторении, внутри Пайтон позвонит next() , что выстрелит в выполнение тело функции contador() до того, чтобы прибывать к первому yield - в этом моменте он возвратит стоимость (которая будет распределена в переменную i), и функция contador он останется в провале (контроль происходит в for ... это значение típíco yield : уступать контроль выполнения над другим трэдом или - в этом случае - частью кода).

Когда iterador вновь будет просить стоимость, взорвется новый next на генераторе, который снова возьмет выполнение до того, чтобы прибывать к предстоящему yield... и я схватил последовательно до тех пор, пока функция не закончится.

Если он у тебя не остается ясным, годится вводить prints в способе, чтобы это видеть хорошо:

def contador(max):
    print("=Dentro de contador - empezando")
    n=0
    while n < max:
        print(f"=Dentro de contador - viene yield con n={n}")
        yield n
        print("=Dentro de contador - retomando después de yield")
        n=n+1
    print("=Dentro de contador - terminando")

print("Instanciando contador") 
mycont = contador(3)
print("Contador instanciado") 

for i in mycont:
    print(f"valor leido del iterador={i}") 
print("Listo") 

Output:

Instanciando contador
Contador instanciado
=Dentro de contador - empezando
=Dentro de contador - viene yield con n=0
valor leido del iterador=0
=Dentro de contador - retomando después de yield
=Dentro de contador - viene yield con n=1
valor leido del iterador=1
=Dentro de contador - retomando después de yield
=Dentro de contador - viene yield con n=2
valor leido del iterador=2
=Dentro de contador - retomando después de yield
=Dentro de contador - terminando
Listo
13
ответ дан 24.11.2019, 14:42
  • 1
    Концепция ничего не считает редким. Редким является синтаксис Пайтона – leonbloy 19.03.2016, 17:53
  • 2
    Он мне не кажется редким. Преимущество, что я вижу его, - для того, чтобы твои программы светили как в programaci и # 243; n функциональный, где ты можешь объявлять бесконечные списки, элементы которых получены слабым способом (lazy) до требования пользователя. Например, в haskell, ты можешь определять список всех они n и # 250; простые положительные целые числа, превосходящие такие 0 как l = [0..] и потом использовать часть элементов этого списка (чем быть вычисленным, и # 225; n в требование) для других операций. Так как s и # 237; различие в случае генераторов состоит в том, что они 1 единственный тип потребления из-за элемента. –  19.03.2016, 22:43
  • 3
    Я не вижу ему редкого. Это м и # 225; s, он делается мне похожим в C # –  20.03.2016, 04:07

Простая одна explicaciГіn что yield, которые могут tambiГ©n быть использованными, чтобы создавать генераторы, как в этом случае, который пишется в одной funciГіn, который использует yield и который функционирует сходно с одним return но важным различием это состоит в том, что он сохраняет ее iteraciГіn, беря как пример твой рукописный шрифт:

def contador(max):
    n=0
    while n < max:
          yield n 
          n=n+1 

Например если instanciamos contador() и мы повторяем на стоимости, которая получает ее funciГіn contador(), можем ощущаться, что оно функционирует как один return, но сохраняет ее iteraciГіn:

contad = contador(10)
for i in contad:
    print("valor: "+str(i))

мы получаем как результат:

valor: 0
valor: 1
valor: 2
valor: 3
valor: 4
valor: 5
valor: 6
valor: 7
valor: 8
valor: 9
5
ответ дан 24.11.2019, 14:42

Есть разы, которые предпочтительно, чтобы функция возвратила результаты по мере того, как он получает их вместо того, чтобы возвращать все вместе в конце Вашего выполнения. Это поручение yield, возвращения стоимости последовательности стоимости. Кроме того, возврати "контроль" над кодом llamante, который решит, если оставаться или нет с выполнением и, даже, делать инъекцию новым данным, чтобы изменять процесс. Это способ, который у него есть python, создания corrutinas, потенциал которого оказался расширенным очень много с последними версиями python и асинхронными процессами. Он достаточно сложный.

Но возвращаясь в вопрос, возможно устанавливать аналогию между функциями и объектами. Определение функции было бы как имение класса с единственным методом, и выполнение функции было бы как создание инстанций класса, чтобы создавать среду выполнения, которое мы называем "закрытием", и которое исчезает, закончив функцию. Использовав yield, мы прерываем выполнение в этой точке, сохраняя инстанцию для Вашего последующего, такого использования до тех пор, пока мы не закончимся.

Например, если ты объявляешь такой генератор:

def contador(max):
    n=0
    while n < max:
            n = yield n
            n=n+1

Чтобы создавать "инстанции" он был бы равно как instanciar объекты:

f = contador(100)
g = contador(20)

Обе инстанции - независимые, с их собственными закрытиями каждые так что выполнение одной не затронет другую.

Начиная со здесь, мы можем действовать с этими инстанциями, чтобы создавать новые iteradores. В модуле itertools обладай хорошей коллекцией полезных. Например, мы можем объединять два генератора в одном, или создавать клонировать генераторы:

import itertools

h = itertools.chain(f, g)
h1, h2 = itertools.tee(h)

Многие из модулей стандартного книжного магазина python они соглашаются iteradores и стоит проверять, какие. Возможный применяться строитель list() и превращать interador в список, но работоспособнее обрабатывать стоимость из-за стоимости по мере того, как они требовались и создавать новые порождающие выражения.

Например, чтобы получать только четные числа h:

pares = (n for n in h if n%2==0)
5
ответ дан 24.11.2019, 14:42