Что делает ключевое слово "yield"?
Каково использование ключевого слова yield
в 9X_listiterator Python? Что он делает?
Например, я пытаюсь 9X_python-shell понять этот код 1 :
def _get_child_candidates(self, distance, min_dist, max_dist): if self._leftchild and distance - max_dist < self._median: yield self._leftchild if self._rightchild and distance + max_dist >= self._median: yield self._rightchild
А это звонящий:
result, candidates = [], [self] while candidates: node = candidates.pop() distance = node._get_dist(obj) if distance <= max_dist and distance >= min_dist: result.extend(node._values) candidates.extend(node._get_child_candidates(distance, min_dist, max_dist)) return result
Что происходит 9X_listiterator при вызове метода _get_child_candidates
? Список возвращается? Единый 9X_python элемент? Это снова называется? Когда прекратятся 9X_py последующие вызовы?
1. Этот фрагмент кода написал Йохен Шульц (jrschulz), который создал отличную библиотеку Python для метрических пространств. Это ссылка на полный источник: [Модуль mspace] [1].
- Смешное количество голосов з ...
Ответ #1
Ответ на вопрос: Что делает ключевое слово "yield"?
Чтобы понять, что делает yield
, вы должны понимать, что 9X_yield-keyword такое генераторы. И прежде чем вы сможете понять генераторы, вы 9X_python должны понять итерации.
Итерационные объекты
Создавая список, вы можете 9X_listiterator читать его элементы один за другим. Чтение 9X_py его элементов по очереди называется итерацией:
>>> mylist = [1, 2, 3] >>> for i in mylist: ... print(i) 1 2 3
mylist
- итерируемый. Когда 9X_iterator вы используете понимание списка, вы создаете 9X_python список и, следовательно, итерируемый:
>>> mylist = [x*x for x in range(3)] >>> for i in mylist: ... print(i) 0 1 4
Все, что 9X_generators вы можете использовать для «for... in...
», является 9X_listiterator итеративным; lists
, strings
, файлы ...
Эти итерации удобны, потому 9X_python что вы можете читать их сколько угодно, но 9X_generators вы храните все значения в памяти, и это 9X_coroutine не всегда то, что вам нужно, когда у вас 9X_iterator много значений.
Генераторы
Генераторы - это итераторы, своего 9X_py рода итерации, которые можно выполнять только один раз. Генераторы не хранят все 9X_iterators значения в памяти, они генерируют значения на лету:
>>> mygenerator = (x*x for x in range(3)) >>> for i in mygenerator: ... print(i) 0 1 4
Это то же самое, за 9X_python-interpreter исключением того, что вы использовали ()
вместо 9X_yield []
. НО, вы не можете выполнить for i in mygenerator
второй раз, поскольку 9X_generator генераторы можно использовать только один 9X_python-shell раз: они вычисляют 0, затем забывают об 9X_iterator этом и вычисляют 1 и заканчивают вычисление 9X_py 4, один за другим.
Доходность
yield
- ключевое слово, которое 9X_coroutine используется как return
, за исключением того, что 9X_yield функция возвращает генератор.
>>> def create_generator(): ... mylist = range(3) ... for i in mylist: ... yield i*i ... >>> mygenerator = create_generator() # create a generator >>> print(mygenerator) # mygenerator is an object! >>> for i in mygenerator: ... print(i) 0 1 4
Это бесполезный 9X_python-interpreter пример, но он удобен, когда вы знаете, что 9X_python-shell ваша функция вернет огромный набор значений, которые 9X_listiterator вам нужно будет прочитать только один раз.
Чтобы 9X_listiterator освоить yield
, вы должны понимать, что при вызове функции код, который вы написали в теле функции, не запускается. Функция 9X_yield-keyword возвращает только объект генератора, это 9X_generators немного сложно.
Затем ваш код будет продолжаться 9X_pythonic с того места, где он остановился, каждый 9X_yield раз, когда for
использует генератор.
Теперь 9X_yield-keyword самое сложное:
Когда for
в первый раз вызывает 9X_generators объект-генератор, созданный из вашей функции, он 9X_coroutine запускает код в вашей функции с самого начала, пока 9X_yield-keyword не достигнет yield
, а затем вернет первое значение 9X_python-interpreter цикла. Затем каждый последующий вызов будет 9X_generator запускать другую итерацию цикла, который 9X_python-interpreter вы написали в функции, и возвращать следующее 9X_python-interpreter значение. Это будет продолжаться до тех 9X_python-shell пор, пока генератор не будет считаться пустым, что 9X_coroutine происходит, когда функция выполняется без 9X_python-shell нажатия yield
. Это может быть связано с тем, что 9X_coroutine цикл подошел к концу или вы больше не удовлетворяете 9X_listiterator "if/else"
.
Объяснение вашего кода
Генератор:
# Here you create the method of the node object that will return the generator def _get_child_candidates(self, distance, min_dist, max_dist): # Here is the code that will be called each time you use the generator object: # If there is still a child of the node object on its left # AND if the distance is ok, return the next child if self._leftchild and distance - max_dist < self._median: yield self._leftchild # If there is still a child of the node object on its right # AND if the distance is ok, return the next child if self._rightchild and distance + max_dist >= self._median: yield self._rightchild # If the function arrives here, the generator will be considered empty # there is no more than two values: the left and the right children
Абонент:
# Create an empty list and a list with the current object reference result, candidates = list(), [self] # Loop on candidates (they contain only one element at the beginning) while candidates: # Get the last candidate and remove it from the list node = candidates.pop() # Get the distance between obj and the candidate distance = node._get_dist(obj) # If distance is ok, then you can fill the result if distance <= max_dist and distance >= min_dist: result.extend(node._values) # Add the children of the candidate in the candidate's list # so the loop will keep running until it will have looked # at all the children of the children of the children, etc. of the candidate candidates.extend(node._get_child_candidates(distance, min_dist, max_dist)) return result
Этот код содержит несколько умных частей:
-
Цикл 9X_iterator повторяется по списку, но список расширяется 9X_generator во время итерации цикла. Это краткий способ 9X_python-interpreter просмотреть все эти вложенные данные, даже 9X_generator если это немного опасно, поскольку вы можете 9X_pythonic получить бесконечный цикл. В этом случае 9X_generators
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
исчерпывает все значения генератора, но 9X_yieldwhile
продолжает создавать новые объекты генератора, которые 9X_yield будут давать значения, отличные от предыдущих, поскольку 9X_pythonista он не применяется к тому же узлу. -
Метод
extend()
- это 9X_iterator метод объекта списка, который ожидает итерацию 9X_pythonic и добавляет свои значения в список.
Обычно 9X_generators мы передаем ему список:
>>> a = [1, 2] >>> b = [3, 4] >>> a.extend(b) >>> print(a) [1, 2, 3, 4]
Но в вашем коде есть 9X_coroutine генератор, и это хорошо, потому что:
- Вам не нужно читать значения дважды.
- У вас может быть много детей, и вы не хотите, чтобы все они хранились в памяти.
И это 9X_python работает, потому что Python не заботится, является 9X_python-shell ли аргумент метода списком или нет. Python 9X_python-shell ожидает итераций, поэтому он будет работать 9X_pythonista со строками, списками, кортежами и генераторами! Это 9X_py называется утиной типизацией и является 9X_pythonic одной из причин, по которой Python такой 9X_python крутой. Но это уже другая история, другой 9X_yield-keyword вопрос ...
Вы можете остановиться на этом 9X_coroutine или прочитать немного, чтобы увидеть расширенное 9X_yield-keyword использование генератора:
Контроль истощения генератора
>>> class Bank(): # Let's create a bank, building ATMs ... crisis = False ... def create_atm(self): ... while not self.crisis: ... yield "$100" >>> hsbc = Bank() # When everything's ok the ATM gives you as much as you want >>> corner_street_atm = hsbc.create_atm() >>> print(corner_street_atm.next()) $100 >>> print(corner_street_atm.next()) $100 >>> print([corner_street_atm.next() for cash in range(5)]) ['$100', '$100', '$100', '$100', '$100'] >>> hsbc.crisis = True # Crisis is coming, no more money! >>> print(corner_street_atm.next()) >>> wall_street_atm = hsbc.create_atm() # It's even true for new ATMs >>> print(wall_street_atm.next()) >>> hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty >>> print(corner_street_atm.next()) >>> brand_new_atm = hsbc.create_atm() # Build a new one to get back in business >>> for cash in brand_new_atm: ... print cash $100 $100 $100 $100 $100 $100 $100 $100 $100 ...
Примечание. Для Python 3 используйте 9X_coroutine print(corner_street_atm.__next__())
или print(next(corner_street_atm))
.
Это может быть полезно для различных 9X_py вещей, например для управления доступом 9X_py к ресурсу.
Itertools, ваш лучший друг
Модуль itertools содержит специальные 9X_py функции для управления итерациями. Вы когда-нибудь 9X_iterator хотели продублировать генератор? Связать 9X_listiterator два генератора? Сгруппировать значения во 9X_pythonic вложенном списке с однострочником? Map / Zip
без 9X_python-shell создания другого списка?
Тогда просто import itertools
.
Пример? Посмотрим 9X_yield-keyword возможные порядки прибытия на скачки на 9X_python-interpreter четырех лошадях:
>>> horses = [1, 2, 3, 4] >>> races = itertools.permutations(horses) >>> print(races) >>> print(list(itertools.permutations(horses))) [(1, 2, 3, 4), (1, 2, 4, 3), (1, 3, 2, 4), (1, 3, 4, 2), (1, 4, 2, 3), (1, 4, 3, 2), (2, 1, 3, 4), (2, 1, 4, 3), (2, 3, 1, 4), (2, 3, 4, 1), (2, 4, 1, 3), (2, 4, 3, 1), (3, 1, 2, 4), (3, 1, 4, 2), (3, 2, 1, 4), (3, 2, 4, 1), (3, 4, 1, 2), (3, 4, 2, 1), (4, 1, 2, 3), (4, 1, 3, 2), (4, 2, 1, 3), (4, 2, 3, 1), (4, 3, 1, 2), (4, 3, 2, 1)]
Понимание внутренних механизмов итерации
Итерация - это процесс, включающий 9X_generator итераторы (реализация метода __iter__()
) и итераторы 9X_pythonic (реализация метода __next__()
). Итерируемые объекты 9X_pythonic - это любые объекты, из которых вы можете 9X_yield-keyword получить итератор. Итераторы - это объекты, которые 9X_python-interpreter позволяют выполнять итерацию по итерациям.
Подробнее 9X_iterators об этом в статье о how for
loops work.
- @MatthiasFripp «Это продолжается до тех пор, пока функция не завершится до конца» - или пока не встретится оператор `return`. (`return` разрешен в функции, содержащей` yie ...
Ответ #2
Ответ на вопрос: Что делает ключевое слово "yield"?
Быстрый путь к пониманию yield
Когда вы видите функцию с операторами yield
, примените 9X_coroutine этот простой трюк, чтобы понять, что произойдет:
- Вставьте строку
result = []
в начало функции. - Замените каждый
yield expr
наresult.append(expr)
. - Вставьте строку
return result
внизу функции. - Ура, больше никаких инструкций
yield
! Прочтите и разберитесь в коде. - Сравните функцию с исходным определением.
Этот 9X_generator трюк может дать вам представление о логике 9X_yield-keyword функции, но то, что на самом деле происходит 9X_coroutine с yield
, значительно отличается от того, что 9X_iterator происходит при подходе на основе списков. Во 9X_generators многих случаях подход yield будет намного 9X_py эффективнее и быстрее. В других случаях 9X_python этот трюк заставит вас застрять в бесконечном 9X_pythonic цикле, даже если исходная функция работает 9X_iterators нормально. Читайте дальше, чтобы узнать 9X_python больше ...
Не путайте свои итерации, итераторы и генераторы
Во-первых, протокол итератора - когда вы пишете
for x in mylist: ...loop body...
Python 9X_iterators выполняет следующие два шага:
-
Получает итератор 9X_yield для
mylist
:Вызов
iter(mylist)
-> возвращает объект с помощью 9X_iterator методаnext()
(или__next__()
в Python 3).[Это шаг, о котором 9X_yield-keyword большинство людей забывают вам рассказывать]
-
Использует 9X_python-shell итератор для перебора элементов:
Продолжайте 9X_generators вызывать метод
next()
на итераторе, возвращенном 9X_python-interpreter с шага 1. Возвращаемое значение изnext()
присваивается 9X_pythonx
, и тело цикла выполняется. Если исключение 9X_coroutineStopIteration
возникает изnext()
, это означает, что в итераторе 9X_iterators больше нет значений и цикл завершен.
На самом 9X_listiterator деле Python выполняет два вышеуказанных 9X_pythonic шага каждый раз, когда ему требуется перебрать содержимое 9X_python-shell объекта - так что это может быть цикл for, но 9X_iterator это также может быть код вроде otherlist.extend(mylist)
( где otherlist
- список 9X_generator Python).
Здесь mylist
- итерируемый, потому что он реализует 9X_coroutine протокол итератора. В определяемом пользователем 9X_python-interpreter классе вы можете реализовать метод __iter__()
, чтобы 9X_iterators сделать экземпляры вашего класса итерируемыми. Этот 9X_python-shell метод должен возвращать итератор. Итератор - это 9X_python-shell объект с методом next()
. Можно реализовать как 9X_python-shell __iter__()
, так и next()
в одном и том же классе, и чтобы 9X_listiterator __iter__()
возвращал self
. Это сработает для простых случаев, но 9X_iterator не тогда, когда вы хотите, чтобы два итератора 9X_pythonic проходили цикл по одному и тому же объекту 9X_python-shell одновременно.
Итак, протокол итератора, многие 9X_listiterator объекты реализуют этот протокол:
- Встроенные списки, словари, кортежи, наборы, файлы.
- Пользовательские классы, реализующие
__iter__()
. - Генераторы.
Обратите 9X_yield-keyword внимание, что цикл for
не знает, с каким объектом 9X_python-interpreter он имеет дело - он просто следует протоколу 9X_python-shell итератора и с радостью получает элемент 9X_generators за элементом при вызове next()
. Встроенные списки 9X_python-interpreter возвращают свои элементы один за другим, словари 9X_iterator возвращают ключи один за другим, файлы возвращают 9X_yield строки одну за другой и т. Д. И генераторы возвращают 9X_py ... ну вот где появляется yield
:
def f123(): yield 1 yield 2 yield 3 for item in f123(): print item
Вместо операторов 9X_yield yield
, если у вас есть три оператора return
в f123()
, будет 9X_listiterator выполнен только первый, и функция завершится. Но 9X_pythonista f123()
- необычная функция. Когда вызывается f123()
, он 9X_iterator не возвращает ни одно из значений в операторах 9X_iterators yield! Он возвращает объект-генератор. Кроме 9X_iterators того, функция действительно не выходит - она 9X_generators переходит в приостановленное состояние. Когда 9X_pythonista цикл for
пытается перебрать объект-генератор, функция 9X_generator возобновляет работу из приостановленного 9X_yield состояния на следующей строке после yield
, из 9X_python-shell которого она ранее возвратилась, выполняет 9X_pythonic следующую строку кода, в данном случае yield
и 9X_python-interpreter возвращает его как следующий элемент. Это 9X_python-shell происходит до тех пор, пока функция не завершится, после 9X_listiterator чего генератор поднимет StopIteration
и цикл не завершится.
Таким 9X_iterators образом, объект-генератор похож на адаптер 9X_yield - с одной стороны, он демонстрирует протокол 9X_iterator итератора, предоставляя методы __iter__()
и next()
, чтобы 9X_coroutine цикл for
оставался счастливым. На другом конце, однако, он 9X_pythonista запускает функцию ровно настолько, чтобы 9X_py получить из нее следующее значение, и возвращает 9X_iterator ее в приостановленный режим.
Зачем нужны генераторы?
Обычно вы можете 9X_python-interpreter написать код, который не использует генераторы, но 9X_iterators реализует ту же логику. Один из вариантов 9X_iterators - использовать «трюк» с временным списком, о 9X_iterators котором я упоминал ранее. Это не будет работать 9X_yield во всех случаях, например, если у вас бесконечные 9X_coroutine циклы, или он может неэффективно использовать 9X_pythonic память, когда у вас действительно длинный 9X_py список. Другой подход - реализовать новый 9X_python итеративный класс SomethingIter, который 9X_py сохраняет состояние в членах экземпляра 9X_py и выполняет следующий логический шаг в своем 9X_python-interpreter методе next()
(или __next__()
в Python 3). В зависимости 9X_python-shell от логики код внутри метода next()
может выглядеть 9X_listiterator очень сложным и быть подверженным ошибкам. Здесь 9X_python генераторы представляют собой простое и 9X_listiterator понятное решение.
- * "Когда вы видите функцию с операторами yield, примените этот просто ...
Ответ #3
Ответ на вопрос: Что делает ключевое слово "yield"?
Подумайте об этом так:
Итератор - это просто 9X_python причудливый термин для объекта, у которого 9X_yield-keyword есть метод next()
. Таким образом, функция yield-ed 9X_python-interpreter выглядит примерно так:
Исходная версия:
def some_function(): for i in xrange(4): yield i for i in some_function(): print i
Это 9X_yield-keyword в основном то, что интерпретатор Python 9X_generator делает с приведенным выше кодом:
class it: def __init__(self): # Start at -1 so that we get 0 when we add 1 below. self.count = -1 # The __iter__ method will be called once by the 'for' loop. # The rest of the magic happens on the object returned by this method. # In this case it is the object itself. def __iter__(self): return self # The next method will be called repeatedly by the 'for' loop # until it raises StopIteration. def next(self): self.count += 1 if self.count < 4: return self.count else: # A StopIteration exception is raised # to signal that the iterator is done. # This is caught implicitly by the 'for' loop. raise StopIteration def some_func(): return it() for i in some_func(): print i
Чтобы лучше 9X_iterators понять, что происходит за кулисами, цикл 9X_python-interpreter for
можно переписать следующим образом:
iterator = some_func() try: while 1: print iterator.next() except StopIteration: pass
Это 9X_listiterator имеет больше смысла или вас больше смущает? :)
Я 9X_pythonista должен отметить, что это чрезмерное упрощение 9X_iterator для иллюстративных целей. :)
- Я пробовал этот пример в Python 3.6, и если я создам `iterator = some_function()`, переменная `iterator` больше не будет иметь функцию с именем` next() `, а только функци ...
Ответ #4
Ответ на вопрос: Что делает ключевое слово "yield"?
Ключевое слово yield
сводится к двум простым 9X_listiterator фактам:
- Если компилятор обнаруживает ключевое слово
yield
где угодно внутри функции, эта функция больше не возвращается с помощью инструкцииreturn
. Вместо этого он немедленно возвращает ленивый объект "ожидающего списка", называемый генератором. - Генератор можно повторять. Что такое итерация? Это что-то вроде
list
илиset
,range
или dict-view со встроенным протоколом для посещения каждого элемента в определенном порядке.
В двух словах: генератор - это отложенный, постепенно ожидающий список, а операторы yield
позволяют использовать нотацию функций для программирования значений списка генератора 9X_generators должен постепенно выплевывать.
generator = myYieldingFunction(...) x = list(generator) generator v [x[0], ..., ???] generator v [x[0], x[1], ..., ???] generator v [x[0], x[1], x[2], ..., ???] StopIteration exception [x[0], x[1], x[2]] done list==[x[0], x[1], x[2]]
Пример
Давайте определим 9X_yield-keyword функцию makeRange
, которая похожа на range
в Python. Вызов 9X_yield makeRange(n)
ВОЗВРАЩАЕТ ГЕНЕРАТОР:
def makeRange(n): # return 0,1,2,...,n-1 i = 0 while i < n: yield i i += 1 >>> makeRange(5)
Чтобы заставить генератор 9X_python-interpreter немедленно возвращать свои ожидающие значения, вы 9X_iterators можете передать его в list()
(так же, как и любой 9X_python-interpreter итерируемый):
>>> list(makeRange(5)) [0, 1, 2, 3, 4]
Пример сравнения с «просто возвращением списка»
Приведенный выше пример можно 9X_python-shell рассматривать как просто создание списка, который 9X_python-shell вы добавляете и возвращаете:
# return a list # # return a generator def makeRange(n): # def makeRange(n): """return [0,1,2,...,n-1]""" # """return 0,1,2,...,n-1""" TO_RETURN = [] # i = 0 # i = 0 while i < n: # while i < n: TO_RETURN += [i] # yield i i += 1 # i += 1 return TO_RETURN # >>> makeRange(5) [0, 1, 2, 3, 4]
Но есть одно 9X_generators существенное отличие; см. последний раздел.
Как можно использовать генераторы
Итерация 9X_iterators - это последняя часть понимания списка, и 9X_coroutine все генераторы являются итеративными, поэтому 9X_generators их часто используют следующим образом:
# < ITERABLE > >>> [x+10 for x in makeRange(5)] [10, 11, 12, 13, 14]
Чтобы 9X_generators лучше понять генераторы, вы можете поэкспериментировать 9X_listiterator с модулем itertools
(обязательно используйте chain.from_iterable
, а 9X_python-shell не chain
, когда это необходимо). Например, вы 9X_generators можете даже использовать генераторы для 9X_python-shell реализации бесконечно длинных ленивых списков, таких 9X_pythonic как itertools.count()
. Вы можете реализовать свой собственный 9X_iterators def enumerate(iterable): zip(count(), iterable)
или, альтернативно, сделать это с помощью 9X_iterators ключевого слова yield
в цикле while.
Обратите 9X_generator внимание: генераторы на самом деле могут 9X_coroutine использоваться для многих других вещей, таких 9X_iterators как implementing coroutines, недетерминированное программирование 9X_listiterator или другие элегантные вещи. Однако представленная 9X_listiterator здесь точка зрения "ленивых списков" - это 9X_generators наиболее распространенное применение, которое 9X_py вы найдете.
За кадром
Так работает «протокол итераций 9X_pythonista Python». То есть, что происходит, когда 9X_yield-keyword вы выполняете list(makeRange(5))
. Это то, что я описал ранее 9X_py как «ленивый, инкрементный список».
>>> x=iter(range(5)) >>> next(x) 0 >>> next(x) 1 >>> next(x) 2 >>> next(x) 3 >>> next(x) 4 >>> next(x) Traceback (most recent call last): File "", line 1, in StopIteration
Встроенная 9X_python-shell функция next()
просто вызывает функцию объектов 9X_pythonic .next()
, которая является частью «протокола итераций» и 9X_coroutine присутствует на всех итераторах. Вы можете 9X_generators вручную использовать функцию next()
(и другие 9X_generators части итерационного протокола) для реализации 9X_python необычных вещей, обычно в ущерб удобочитаемости, поэтому 9X_coroutine старайтесь этого не делать ...
Детали
Обычно большинство 9X_python-interpreter людей не заботятся о следующих различиях 9X_coroutine и, вероятно, захотят перестать читать здесь.
В 9X_python-shell языке Python итератором является любой объект, который 9X_python-interpreter «понимает концепцию цикла for», например 9X_generators список [1,2,3]
, а итератор - это конкретный экземпляр запрошенного 9X_py цикла for, например [1,2,3].__iter__()
. Генератор точно такой же, как 9X_iterator и любой итератор, за исключением того, как 9X_iterators он был написан (с синтаксисом функции).
Когда 9X_python-interpreter вы запрашиваете итератор из списка, он создает 9X_python новый итератор. Однако, когда вы запрашиваете 9X_iterators итератор у итератора (что вы делаете редко), он 9X_pythonic просто дает вам свою копию.
Таким образом, в 9X_coroutine том маловероятном случае, если вы не сможете 9X_listiterator сделать что-то подобное ...
> x = myRange(5) > list(x) [0, 1, 2, 3, 4] > list(x) []
... тогда помните, что 9X_python-shell генератор - это итератор; то есть одноразового использования. Если 9X_py вы хотите использовать его повторно, вам 9X_generators следует снова вызвать myRange(...)
. Если вам нужно использовать 9X_pythonista результат дважды, преобразуйте результат 9X_coroutine в список и сохраните его в переменной x = list(myRange(5))
. Те, кому 9X_python абсолютно необходимо клонировать генератор 9X_iterators (например, кто делает ужасающе хакерское 9X_python метапрограммирование), могут использовать 9X_generator itertools.tee
(still works in Python 3) в случае крайней необходимости, поскольку 9X_pythonista copyable iterator Python PEP standards proposal был отложен.
Ответ #5
Ответ на вопрос: Что делает ключевое слово "yield"?
Что делает ключевое слово
yield
в Python?Краткое содержание ответа
- Функция с
yield
при вызове возвращает Generator.- Генераторы являются итераторами, потому что они реализуют iterator protocol, поэтому вы можете перебирать их.
- Генератор также может отправлять информацию, что делает его концептуально сопрограммой.
- В Python 3 вы можете делегировать от одного генератора к другому в обоих направлениях с помощью
yield from
.- (В приложении критикуется пара ответов, включая верхний, и обсуждается использование
return
в генераторе.)Генераторы:
yield
разрешен только внутри определения функции, а 9X_py включениеyield
в определение функции заставляет его возвращать генератор.Идея генераторов пришла из других языков 9X_yield-keyword (см. сноску 1) с различными реализациями. В 9X_generators генераторах Python выполнение кода - frozen в 9X_yield точке yield. Когда вызывается генератор 9X_generator (методы обсуждаются ниже), выполнение возобновляется 9X_python-shell и затем останавливается при следующем выходе.
yield
предоставляет простой 9X_generators способ implementing the iterator protocol, определяемый следующими двумя методами:__iter__
и 9X_listiteratornext
(Python 2) или__next__
(Python 3). Оба эти метода сделать 9X_coroutine объект итератором, который можно было бы 9X_generators проверить с помощью абстрактной базыIterator
Класс 9X_python-interpreter из модуляcollections
.>>> def func(): ... yield 'I am' ... yield 'a generator!' ... >>> type(func) # A function with yield is still a function >>> gen = func() >>> type(gen) # but it returns a generator >>> hasattr(gen, '__iter__') # that's an iterable True >>> hasattr(gen, 'next') # and with .next (.__next__ in Python 3) True # implements the iterator protocol.
Тип генератора - это подтип итератора:
>>> import collections, types >>> issubclass(types.GeneratorType, collections.Iterator) True
А 9X_python при необходимости мы можем проверить тип 9X_python-interpreter следующим образом:
>>> isinstance(gen, types.GeneratorType) True >>> isinstance(gen, collections.Iterator) True
Функция
Iterator
is that once exhausted, вы не можете 9X_listiterator повторно использовать или сбросить ее:>>> list(gen) ['I am', 'a generator!'] >>> list(gen) []
Вам 9X_yield придется сделать еще один, если вы хотите 9X_python снова использовать его функции (см. сноску 9X_yield 2):
>>> list(func()) ['I am', 'a generator!']
Данные можно получить программно, например:
def func(an_iterable): for item in an_iterable: yield item
Вышеупомянутый 9X_python-shell простой генератор также эквивалентен приведенному 9X_yield-keyword ниже - начиная с Python 3.3 (и недоступен 9X_listiterator в Python 2), вы можете использовать
yield from
:def func(an_iterable): yield from an_iterable
Однако 9X_python-shell
yield from
также позволяет делегировать субгенераторам, которые 9X_iterators будут объяснены в следующем разделе о совместном 9X_python-interpreter делегировании с подпрограммами.Сопрограммы:
yield
формирует 9X_iterators выражение, которое позволяет отправлять 9X_yield-keyword данные в генератор (см. сноску 3)Вот пример, обратите 9X_py внимание на переменную
received
, которая будет указывать 9X_yield-keyword на данные, отправляемые в генератор:def bank_account(deposited, interest_rate): while True: calculated_interest = interest_rate * deposited received = yield calculated_interest if received: deposited += received >>> my_account = bank_account(1000, .05)
Во-первых, мы 9X_generator должны поставить генератор в очередь с помощью 9X_python встроенной функции
next
. Так и будет вызвать 9X_pythonista соответствующий методnext
или__next__
, в зависимости 9X_pythonista от версии Python, который вы используете:>>> first_year_interest = next(my_account) >>> first_year_interest 50.0
И 9X_coroutine теперь мы можем отправлять данные в генератор. (Sending
None
is the same as callingnext
.):>>> next_year_interest = my_account.send(first_year_interest + 1000) >>> next_year_interest 102.5
Совместное делегирование подпрограмм с
yield from
Напомним, что 9X_python
yield from
доступен в Python 3. Это позволяет нам 9X_coroutine делегировать сопрограммы подпрограмме:def money_manager(expected_rate): # must receive deposited value from .send(): under_management = yield # yield None to start. while True: try: additional_investment = yield expected_rate * under_management if additional_investment: under_management += additional_investment except GeneratorExit: '''TODO: write function to send unclaimed funds to state''' raise finally: '''TODO: write function to mail tax info to client''' def investment_account(deposited, manager): '''very simple model of an investment account that delegates to a manager''' # must queue up manager: next(manager) # <- same as manager.send(None) # This is where we send the initial deposit to the manager: manager.send(deposited) try: yield from manager except GeneratorExit: return manager.close() # delegate?
И 9X_py теперь мы можем делегировать функциональность 9X_yield подгенератору, и его можно использовать генератором, как 9X_python указано выше:
my_manager = money_manager(.06) my_account = investment_account(1000, my_manager) first_year_return = next(my_account) # -> 60.0
Теперь смоделируйте добавление 9X_python-interpreter еще 1000 к счету плюс возврат по счету (60,0):
next_year_return = my_account.send(first_year_return + 1000) next_year_return # 123.6
Вы 9X_generator можете узнать больше о точной семантике 9X_pythonic
yield from
в PEP 380.Другие методы: закрыть и выбросить
Метод
close
вызываетGeneratorExit
в точке, где функция казнь 9X_python-shell была заморожена. Это также будет вызываться 9X_iterator__del__
, чтобы вы можно поместить любой код очистки 9X_py там, где вы обрабатываетеGeneratorExit
:my_account.close()
Вы также можете 9X_python-shell вызвать исключение, которое может быть обработано 9X_python-interpreter в генераторе. или передается обратно пользователю:
import sys try: raise ValueError except: my_manager.throw(*sys.exc_info())
Повышает:
Traceback (most recent call last): File "", line 4, in File "", line 6, in money_manager File "", line 2, in ValueError
Заключение
Мне 9X_listiterator кажется, я рассмотрел все аспекты следующего 9X_generators вопроса:
Что делает ключевое слово
yield
в Python?Оказывается,
yield
многое делает. Я уверен, что 9X_iterators могу добавить еще подробные примеры к этому. Если 9X_python вы хотите большего или у вас есть конструктивная 9X_iterator критика, дайте мне знать, комментируя ниже.
Приложение:
Критика самого популярного / принятого ответа **
- Он не понимает, что делает итерируемым, просто используя список в качестве примера. См. Мои ссылки выше, но вкратце: итерация имеет метод
__iter__
, возвращающий итератор. Итератор предоставляет метод.next
(Python 2 или.__next__
(Python 3), который неявно вызывается цикламиfor
до тех пор, пока он не вызоветStopIteration
, и как только это произойдет, он будет продолжать делать это.- Затем он использует выражение генератора, чтобы описать, что такое генератор. Поскольку генератор - это просто удобный способ создания итератора, он только сбивает с толку, и мы еще не дошли до части
yield
.- В разделе Контроль истощения генератора он вызывает метод
.next
, тогда как вместо этого он должен использовать встроенную функциюnext
. Это был бы подходящий уровень косвенного обращения, потому что его код не работает в Python 3.- Itertools? Это вообще не имело отношения к тому, что делает
yield
.- Никакого обсуждения методов, которые
yield
предоставляет вместе с новой функциональностьюyield from
в Python 3. Самый популярный / принятый ответ - очень неполный ответ.Критика ответа, предлагающего
yield
в выражении или понимании генератора.Грамматика 9X_python в настоящее время допускает любое выражение 9X_yield в понимании списка.
expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*) ... yield_expr: 'yield' [yield_arg] yield_arg: 'from' test | testlist
Поскольку yield является 9X_pythonic выражением, некоторые считают его интересным 9X_pythonic для использования в понимании или выражении 9X_py генератора, несмотря на то, что здесь не 9X_pythonic упоминается особо удачный вариант использования.
Основными 9X_pythonista разработчиками CPython являются discussing deprecating its allowance. Вот соответствующее 9X_pythonic сообщение из списка рассылки:
30 января 2017 9X_iterators г. в 19:05 Бретт Кэннон написал:
Вс, 29 января 9X_iterator 2017 г., 16:39 Крейг Родригес написал:
Я 9X_listiterator согласен с любым подходом. Оставить вещи 9X_python такими, какие они есть в Python 3 не годится, ИМХО.
Мой 9X_listiterator голос: это SyntaxError, поскольку вы не 9X_yield-keyword получаете того, от чего ожидаете. синтаксис.
Я 9X_generator согласен, что это разумное место для нас, поскольку 9X_yield-keyword любой код полагаться на текущее поведение 9X_python-interpreter действительно слишком умно, чтобы быть ремонтопригодный.
Для 9X_yield этого нам, вероятно, понадобится:
- SyntaxWarning или DeprecationWarning в 3.7
- Предупреждение Py3k в 2.7.x
- SyntaxError в 3.8
Ура, Ник.
- Ник 9X_listiterator Коглан | ncoghlan на gmail.com | Брисбен, Австралия
Кроме 9X_iterators того, существует outstanding issue (10544), который, похоже, указывает 9X_python-shell на то, что это никогда не будет хорошей идеей (PyPy, реализация 9X_pythonic Python, написанная на Python, уже вызывает 9X_coroutine синтаксические предупреждения.)
Итог, пока 9X_yield-keyword разработчики CPython не сообщат нам иное: Не помещайте
yield
в выражение или понимание генератора.Оператор
return
в генератореВ 9X_pythonista Python 2:
В функции генератора оператор
return
не может 9X_listiterator включатьexpression_list
. В этом контексте пустойreturn
означает, что 9X_yield генератор готов и вызовет активациюStopIteration
.
expression_list
- это, по 9X_coroutine сути, любое количество выражений, разделенных 9X_python-interpreter запятыми. По сути, в Python 2 вы можете 9X_python-shell остановить генератор с помощьюreturn
, но вы не 9X_pythonic можете вернуть значение.В Python 3:
В функции генератора 9X_pythonista оператор
return
указывает, что генератор готов, и 9X_coroutine вызывает вызовStopIteration
. Возвращаемое значение (если 9X_generator есть) используется в качестве аргумента 9X_py для созданияStopIteration
и становится атрибутомStopIteration.value
.Сноски
Языки CLU, Sather и Icon упоминались в предложении познакомить с концепцией генераторов в Python. Общая идея такова что функция может поддерживать внутреннее состояние и давать промежуточные точки данных по запросу пользователя. Это обещал быть superior in performance to other approaches, including Python threading, который даже недоступен в некоторых системах.
Это означает, например, что объекты
range
не являются объектамиIterator
, даже если они итерируемы, потому что их можно использовать повторно. Как и списки, их методы__iter__
возвращают объекты-итераторы.
yield
изначально 9X_py был введен как оператор, что означает, что 9X_pythonic он может появляться только в начале строки 9X_generators в блоке кода. Теперьyield
создает выражение 9X_listiterator доходности. https://docs.python.org/2/reference/simple_stmts.html#grammar-token-yield_stmt Это изменение было proposed, чтобы 9X_generator позволить пользователю отправлять данные 9X_py в генератор так же, как его можно было получить. Чтобы 9X_python-interpreter отправлять данные, нужно уметь их чему-то 9X_generators назначить, и для этого инструкция просто 9X_python-shell не сработает.
Ответ #6
Ответ на вопрос: Что делает ключевое слово "yield"?
yield
похож на return
- он возвращает все, что вы ему 9X_yield скажете (как генератор). Разница в том, что 9X_generators при следующем вызове генератора выполнение 9X_py начинается с последнего вызова оператора 9X_python-interpreter yield
. В отличие от return, кадр стека не очищается при возникновении yield, однако управление передается обратно вызывающей стороне, поэтому его состояние возобновится при следующем вызове функции.
В случае вашего кода 9X_yield функция get_child_candidates
действует как итератор, поэтому 9X_generator при расширении списка он добавляет по одному 9X_python элементу в новый список.
list.extend
вызывает итератор, пока 9X_py он не будет исчерпан. В случае опубликованного 9X_listiterator вами образца кода было бы гораздо проще 9X_listiterator просто вернуть кортеж и добавить его в список.
- Это близко, но неверно. Каждый раз, когда вы вызываете функцию с выражением yield в ней, она возвращает новый объект-генератор. Только когда вы вызываете метод этого генератора .next(), выполнение возобновляется ...
Ответ #7
Ответ на вопрос: Что делает ключевое слово "yield"?
Следует упомянуть еще одну вещь: функция, которая 9X_yield дает результат, на самом деле не должна 9X_listiterator завершаться. Я написал такой код:
def fib(): last, cur = 0, 1 while True: yield cur last, cur = cur, last + cur
Тогда я 9X_generators могу использовать его в другом коде, например:
for f in fib(): if some_condition: break coolfuncs(f);
Это 9X_yield действительно помогает упростить некоторые 9X_generators проблемы и упрощает работу с некоторыми 9X_yield вещами.
Ответ #8
Ответ на вопрос: Что делает ключевое слово "yield"?
Для тех, кто предпочитает минималистичный 9X_python рабочий пример, подумайте об этом интерактивном 9X_python-interpreter сеансе Python:
>>> def f(): ... yield 1 ... yield 2 ... yield 3 ... >>> g = f() >>> for i in g: ... print(i) ... 1 2 3 >>> for i in g: ... print(i) ... >>> # Note that this time nothing was printed
Ответ #9
Ответ на вопрос: Что делает ключевое слово "yield"?
TL; DR
Вместо этого:
def square_list(n): the_list = [] # Replace for x in range(n): y = x * x the_list.append(y) # these return the_list # lines
сделайте это:
def square_yield(n): for x in range(n): y = x * x yield y # with this one.
Когда вы создаете список с нуля, yield
вместо 9X_python-shell этого используйте каждую часть.
Это был мой 9X_listiterator первый "ага" момент с yield.
yield
- это 9X_python-interpreter sugary способ сказать
создать серию вещей
Такое 9X_iterators же поведение:
>>> for square in square_list(4): ... print(square) ... 0 1 4 9 >>> for square in square_yield(4): ... print(square) ... 0 1 4 9
Другое поведение:
Результат 9X_pythonista - однопроходный: можно выполнить итерацию только один 9X_iterators раз. Когда функция имеет yield, мы называем 9X_iterators ее generator function. И iterator - это то, что он возвращает. Эти 9X_pythonista термины показательны. Мы теряем удобство 9X_yield контейнера, но получаем силу ряда, вычисляемого 9X_generator по мере необходимости и произвольно длинной.
Доходность 9X_generators ленивая, она откладывает вычисления. Функция с 9X_generators yield в ней на самом деле вообще не выполняется, когда вы ее вызываете. Она возвращает iterator object, который запоминает, где 9X_coroutine она остановилась. Каждый раз, когда вы вызываете 9X_python-interpreter next()
на итераторе (это происходит в цикле for), выполнение 9X_pythonic смещается вперед до следующего yield. return
вызывает 9X_python-shell StopIteration и завершает серию (это естественный 9X_coroutine конец цикла for).
Доходность разносторонняя. Данные не 9X_yield нужно хранить все вместе, их можно делать 9X_listiterator доступными по отдельности. Оно может быть 9X_generator бесконечным.
>>> def squares_all_of_them(): ... x = 0 ... while True: ... yield x * x ... x += 1 ... >>> squares = squares_all_of_them() >>> for _ in range(4): ... print(next(squares)) ... 0 1 4 9
Если вам нужно несколько проходов и серия не слишком 9X_generator длинная, просто вызовите для нее list()
:
>>> list(square_yield(4)) [0, 1, 4, 9]
Отличный 9X_python-shell выбор слова yield
, потому что both meanings применимо:
yield - производить 9X_python или обеспечивать (как в сельском хозяйстве)
... укажите 9X_iterators следующие данные в серии.
yield - уступить дорогу 9X_iterators или отказаться (как в случае политической 9X_python власти)
... прекращать выполнение ЦП, пока 9X_coroutine итератор не продвинется вперед.
Ответ #10
Ответ на вопрос: Что делает ключевое слово "yield"?
Yield дает вам генератор.
def get_odd_numbers(i): return range(1, i, 2) def yield_odd_numbers(i): for x in range(1, i, 2): yield x foo = get_odd_numbers(10) bar = yield_odd_numbers(10) foo [1, 3, 5, 7, 9] bar bar.next() 1 bar.next() 3 bar.next() 5
Как видите, в первом 9X_yield случае foo
хранит в памяти сразу весь список. Это 9X_pythonista не имеет большого значения для списка из 9X_generators 5 элементов, но что, если вам нужен список 9X_iterator из 5 миллионов? Это не только пожирает много 9X_listiterator памяти, но и требует много времени для создания 9X_python-interpreter во время вызова функции.
Во втором случае 9X_coroutine bar
просто предоставляет вам генератор. Генератор 9X_pythonista является итеративным - это означает, что 9X_python-shell вы можете использовать его в цикле for
и т. Д., Но 9X_python-interpreter к каждому значению можно получить доступ 9X_python только один раз. Все значения также не сохраняются 9X_pythonista в памяти одновременно; объект-генератор 9X_pythonic «запоминает», где он был в цикле в последний 9X_pythonista раз, когда вы его вызывали - таким образом, если 9X_pythonic вы используете итерацию для (скажем) подсчета 9X_python-interpreter до 50 миллиардов, вам не нужно считать до 9X_generators 50 миллиардов все сразу и сохраните 50 миллиардов 9X_coroutine чисел для подсчета.
Опять же, это довольно 9X_listiterator надуманный пример. Вы, вероятно, использовали 9X_python-shell бы itertools, если бы действительно хотели 9X_python-shell сосчитать до 50 миллиардов. :)
Это самый 9X_yield-keyword простой вариант использования генераторов. Как 9X_python-interpreter вы сказали, его можно использовать для написания 9X_python эффективных перестановок, используя yield 9X_python для проталкивания вещей через стек вызовов 9X_generators вместо использования какой-либо переменной 9X_iterator стека. Генераторы также могут использоваться 9X_python-shell для специализированного обхода дерева и 9X_py для многих других вещей.
- Просто примечание - в Python 3 `range` также возвращает генератор вместо списка, по ...
Ответ #11
Ответ на вопрос: Что делает ключевое слово "yield"?
Возвращает генератор. Я не особо знаком 9X_yield-keyword с Python, но считаю, что это то же самое, что 9X_python и C#'s iterator blocks, если вы знакомы с ними.
Ключевая идея 9X_generator состоит в том, что компилятор / интерпретатор 9X_yield-keyword / что-то еще делает некоторую уловку, так 9X_yield-keyword что, что касается вызывающего абонента, он 9X_iterators может продолжать вызывать next(), и он будет 9X_python-interpreter продолжать возвращать значения - , как если бы метод генератора был приостановлено. Теперь 9X_listiterator очевидно, что вы не можете действительно 9X_coroutine «приостановить» метод, поэтому компилятор 9X_python-shell создает конечный автомат, чтобы вы запомнили, где 9X_py вы сейчас находитесь, как выглядят локальные 9X_yield-keyword переменные и т. Д. Это намного проще, чем 9X_iterators написать итератор самостоятельно.
Ответ #12
Ответ на вопрос: Что делает ключевое слово "yield"?
Есть один тип ответа, который, как мне кажется, еще 9X_python не дан, среди множества отличных ответов, описывающих, как 9X_py использовать генераторы. Вот ответ теории 9X_yield-keyword языка программирования:
Оператор yield
в Python 9X_iterators возвращает генератор. Генератор в Python 9X_python-shell - это функция, которая возвращает продолжения (и, в 9X_pythonista частности, тип сопрограммы, но продолжения 9X_iterator представляют собой более общий механизм 9X_coroutine для понимания того, что происходит).
Продолжения 9X_pythonic в теории языков программирования - это гораздо 9X_pythonista более фундаментальный вид вычислений, но 9X_python-interpreter они используются не часто, потому что их 9X_python чрезвычайно сложно осмыслить, а также очень 9X_coroutine сложно реализовать. Но идея того, что такое 9X_yield продолжение, проста: это состояние вычисления, которое 9X_iterators еще не завершено. В этом состоянии сохраняются 9X_coroutine текущие значения переменных, операции, которые 9X_coroutine еще предстоит выполнить, и так далее. Затем 9X_yield-keyword в какой-то момент позже в программе может 9X_generators быть вызвано продолжение, так что переменные 9X_python-shell программы будут сброшены в это состояние 9X_python и будут выполнены операции, которые были 9X_python-shell сохранены.
Продолжение в этой более общей 9X_generators форме может быть реализовано двумя способами. В 9X_iterator способе call/cc
стек программы буквально сохраняется, а 9X_yield затем, когда вызывается продолжение, стек 9X_yield-keyword восстанавливается.
В стиле передачи продолжения 9X_python-shell (CPS) продолжения - это просто обычные функции 9X_pythonista (только в языках, где функции являются первоклассными), которыми 9X_python программист явно управляет и передает подпрограммам. В 9X_yield-keyword этом стиле состояние программы представлено 9X_yield замыканиями (и переменными, которые в них 9X_yield-keyword закодированы), а не переменными, которые 9X_pythonic находятся где-то в стеке. Функции, управляющие 9X_python-shell потоком управления, принимают продолжение 9X_python-shell в качестве аргументов (в некоторых вариантах 9X_yield-keyword CPS функции могут принимать несколько продолжений) и 9X_generator манипулируют потоком управления, вызывая 9X_listiterator их, просто вызывая их и возвращая впоследствии. Вот 9X_python очень простой пример стиля передачи продолжения:
def save_file(filename): def write_file_continuation(): write_stuff_to_file(filename) check_if_file_exists_and_user_wants_to_overwrite(write_file_continuation)
В 9X_listiterator этом (очень упрощенном) примере программист 9X_python сохраняет операцию фактической записи файла 9X_coroutine в продолжение (что потенциально может быть 9X_py очень сложной операцией, требующей записи 9X_python-shell множества деталей), а затем передает это 9X_listiterator продолжение (т. е. как первоклассное закрытие) другому 9X_yield оператору, который выполняет дополнительную 9X_python обработку, а затем вызывает его при необходимости. (Я 9X_generators часто использую этот шаблон проектирования 9X_py в реальном программировании графического 9X_python-shell интерфейса пользователя, либо потому, что 9X_yield он экономит мне строки кода, либо, что более 9X_generators важно, для управления потоком управления 9X_python-interpreter после срабатывания событий графического 9X_yield интерфейса.)
Остальная часть этого поста 9X_yield-keyword будет, без потери общности, концептуализировать 9X_iterator продолжения как CPS, потому что это чертовски 9X_yield легче понять и прочитать.
Теперь поговорим 9X_python-shell о генераторах в Python. Генераторы - это 9X_yield особый подтип продолжения. В то время как 9X_pythonista продолжения обычно могут сохранять состояние вычисления (т. Е. Стек вызовов программы), генераторы могут сохранять состояние итерации только на итератор. Хотя 9X_yield-keyword это определение немного вводит в заблуждение 9X_listiterator для некоторых случаев использования генераторов. Например:
def f(): while True: yield 4
Очевидно, что 9X_python-interpreter это разумная итерация, поведение которой 9X_iterator четко определено - каждый раз, когда генератор 9X_coroutine выполняет итерацию, он возвращает 4 (и делает 9X_pythonista это всегда). Но, вероятно, при мысли об 9X_py итераторах приходит на ум не прототип итерируемого 9X_py объекта (т. Е. for x in collection: do_something(x)
). Этот пример иллюстрирует 9X_yield возможности генераторов: если что-то является 9X_python-interpreter итератором, генератор может сохранить состояние 9X_yield-keyword своей итерации.
Повторюсь: продолжения могут 9X_yield сохранять состояние стека программы, а генераторы 9X_coroutine могут сохранять состояние итерации. Это 9X_yield-keyword означает, что продолжения намного мощнее 9X_py генераторов, но также и генераторы намного 9X_generator проще. Разработчику языка их легче реализовать, и 9X_python-shell программисту легче их использовать (если 9X_iterators у вас есть время, чтобы записать, попробуйте 9X_generator прочитать и понять this page about continuations and call/cc).
Но вы можете легко 9X_py реализовать (и концептуализировать) генераторы 9X_python-interpreter как простой, конкретный случай стиля передачи 9X_python-interpreter продолжения:
Каждый раз, когда вызывается 9X_python-interpreter yield
, он сообщает функции, что нужно вернуть 9X_pythonic продолжение. Когда функция вызывается снова, она 9X_python-interpreter начинается с того места, где была остановлена. Итак, в 9X_python-interpreter псевдопсевдокоде (т.е. не в псевдокоде, но 9X_listiterator не в коде) метод генератора next
в основном 9X_py выглядит следующим образом:
class Generator(): def __init__(self,iterable,generatorfun): self.next_continuation = lambda:generatorfun(iterable) def next(self): value, next_continuation = self.next_continuation() self.next_continuation = next_continuation return value
где ключевое 9X_py слово yield
на самом деле является синтаксическим 9X_pythonic сахаром для реальной функции генератора, в 9X_generator основном что-то вроде:
def generatorfun(iterable): if len(iterable) == 0: raise StopIteration else: return (iterable[0], lambda:generatorfun(iterable[1:]))
Помните, что это всего 9X_pythonic лишь псевдокод, и фактическая реализация 9X_iterator генераторов в Python более сложна. Но в 9X_pythonista качестве упражнения, чтобы понять, что происходит, попробуйте 9X_yield-keyword использовать стиль передачи продолжения 9X_iterators для реализации объектов генератора без использования 9X_pythonic ключевого слова yield
.
Ответ #13
Ответ на вопрос: Что делает ключевое слово "yield"?
Вот пример на простом языке. Я покажу соответствие 9X_coroutine между высокоуровневыми человеческими концепциями 9X_py и низкоуровневыми концепциями Python.
Я хочу 9X_iterators оперировать последовательностью чисел, но 9X_iterators не хочу утруждать себя созданием этой последовательности, я 9X_python-interpreter хочу сосредоточиться только на операции, которую 9X_pythonic хочу выполнить. Итак, делаю следующее:
- Я звоню вам и говорю, что мне нужна определенная последовательность чисел, и я сообщаю вам, каков алгоритм.
Этот шаг соответствуетdef
включению функции генератора, то есть функции, содержащейyield
. - Через некоторое время я скажу вам: «Хорошо, приготовьтесь назвать мне последовательность цифр».
Этот шаг соответствует вызову функции генератора, которая возвращает объект-генератор. Обратите внимание, что вы пока не называете мне никаких чисел; вы просто берете бумагу и карандаш. - Я прошу вас: «Назовите мне следующий номер», а вы назовите мне первое число; после этого вы ждете, пока я спрошу у вас следующий номер. Ваша задача - вспомнить, где вы были, какие числа вы уже сказали и какое будет следующее число. Меня не волнуют детали.
Этот шаг соответствует вызову.next()
для объекта-генератора. - … повторять предыдущий шаг, пока…
- в конце концов, вам может прийти конец. Вы не называете мне номер; вы просто кричите: «Держите лошадей! Я закончил! Больше никаких номеров!»
Этот шаг соответствует завершению работы объекта-генератором и возникновению исключенияStopIteration
. Функция генератора не должна вызывать исключение. Он возникает автоматически, когда функция завершается или выдаетreturn
.
Это 9X_iterators то, что делает генератор (функция, содержащая 9X_yield yield
); он начинает выполнение, приостанавливается 9X_python всякий раз, когда он выполняет yield
, а при запросе 9X_coroutine значения .next()
он продолжает с того места, где 9X_generators он был последним. Он идеально сочетается 9X_generator по дизайну с протоколом итератора Python, который 9X_generators описывает, как последовательно запрашивать 9X_yield значения.
Самым известным пользователем протокола 9X_iterators итератора является команда for
в Python. Итак, всякий 9X_pythonic раз, когда вы делаете:
for item in sequence:
не имеет значения, является 9X_python-shell ли sequence
списком, строкой, словарем или генератором 9X_generator объектом, как описано выше; результат тот же: вы 9X_iterators читаете элементы последовательно один за 9X_py другим.
Обратите внимание, что def
создание 9X_listiterator функции, содержащей ключевое слово yield
, - не 9X_yield-keyword единственный способ создать генератор; это 9X_iterators самый простой способ создать его.
Для получения 9X_python-shell более точной информации прочтите о iterator types, yield statement и 9X_iterators generators в документации Python.
Ответ #14
Ответ на вопрос: Что делает ключевое слово "yield"?
Хотя многие ответы показывают, почему вы 9X_listiterator должны использовать yield
для создания генератора, для 9X_python-shell yield
есть больше применений. Создать сопрограмму, которая 9X_python-shell позволяет передавать информацию между двумя 9X_python-shell блоками кода, довольно просто. Я не буду 9X_pythonic повторять какие-либо из уже приведенных 9X_generator прекрасных примеров использования yield
для создания 9X_yield-keyword генератора.
Чтобы понять, что делает yield
в следующем 9X_python-interpreter коде, вы можете пальцем проследить цикл 9X_python через любой код, имеющий yield
. Каждый раз, когда 9X_coroutine ваш палец касается yield
, вы должны ждать ввода 9X_pythonista next
или send
. Когда вызывается next
, вы отслеживаете 9X_python код до тех пор, пока не нажмете yield
... код 9X_python справа от yield
оценивается и возвращается вызывающей 9X_generator стороне ... затем вы ждете. Когда next
вызывается 9X_yield-keyword снова, вы выполняете еще один цикл по коду. Однако 9X_pythonic вы заметите, что в сопрограмме yield
также можно 9X_python-interpreter использовать с send
…, который отправит значение 9X_python от вызывающего в функцию вывода. Если задан 9X_python-shell send
, тогда yield
получает отправленное значение 9X_python-interpreter и выплевывает его в левую часть ... тогда 9X_yield-keyword трассировка кода продолжается до тех пор, пока 9X_iterators вы снова не нажмете yield
(возвращая значение 9X_pythonista в конце, как если был вызван next
).
Например:
>>> def coroutine(): ... i = -1 ... while True: ... i += 1 ... val = (yield i) ... print("Received %s" % val) ... >>> sequence = coroutine() >>> sequence.next() 0 >>> sequence.next() Received None 1 >>> sequence.send('hello') Received hello 2 >>> sequence.close()
- Милый! [Батут] (https://en.wikipedia.org/wiki/Trampoline_ (вычисления)) (в смысле Лиспа). Нечасто их видишь!<p ...
Ответ #15
Ответ на вопрос: Что делает ключевое слово "yield"?
Существует еще одно использование и значение 9X_python-shell yield
(начиная с Python 3.3):
yield from
От PEP 380 -- Syntax for Delegating to a Subgenerator:
Синтаксис предлагается 9X_generators генератору делегировать часть своих операций 9X_yield другому генератору. Это позволяет выделить 9X_coroutine часть кода, содержащую «yield», и поместить 9X_py ее в другой генератор. Кроме того, подгенератору 9X_iterator разрешено возвращать значение, и значение 9X_coroutine становится доступным для делегирующего генератора.
Новый 9X_coroutine синтаксис также открывает некоторые возможности 9X_generators для оптимизации, когда один генератор повторно 9X_python-interpreter возвращает значения, созданные другим.
Кроме 9X_generator того, this представит (начиная с Python 3.5):
async def new_coroutine(data): ... await blocking_action()
, чтобы 9X_generator не путать сопрограммы с обычным генератором 9X_pythonista (сегодня yield
используется в обоих).
Ответ #16
Ответ на вопрос: Что делает ключевое слово "yield"?
Все ответы отличные, но для новичков это 9X_listiterator немного сложно.
Я полагаю, вы выучили инструкцию 9X_python return
.
По аналогии, return
и yield
- близнецы. return
означает 9X_python-interpreter «возврат и остановка», тогда как «yield» означает 9X_pythonic «вернуться, но продолжить»
- Попробуйте получить num_list с помощью
return
.
def num_list(n): for i in range(n): return i
Запустить:
In [5]: num_list(3) Out[5]: 0
Видите 9X_iterator ли, вы получаете только одно число, а не 9X_generators их список. return
никогда не позволяет вам успешно 9X_generators преобладать, просто реализует один раз и 9X_listiterator выходит.
- Приходит
yield
Замените return
на yield
:
In [10]: def num_list(n): ...: for i in range(n): ...: yield i ...: In [11]: num_list(3) Out[11]: In [12]: list(num_list(3)) Out[12]: [0, 1, 2]
Теперь вы выигрываете, чтобы 9X_generators получить все числа.
По сравнению с return
, который 9X_yield-keyword запускается один раз и останавливается, yield
выполняется 9X_listiterator запланированное вами время. Вы можете интерпретировать 9X_python-interpreter return
как return one of them
, а yield
как return all of them
. Это называется iterable
.
- Еще один шаг: мы можем переписать инструкцию
yield
с помощьюreturn
In [15]: def num_list(n): ...: result = [] ...: for i in range(n): ...: result.append(i) ...: return result In [16]: num_list(3) Out[16]: [0, 1, 2]
Это суть 9X_coroutine yield
.
Разница между выводом списка return
и выводом 9X_python объекта yield
заключается в следующем:
Вы всегда 9X_iterators будете получать [0, 1, 2] из объекта списка, но 9X_py сможете получить их только один раз из «вывода 9X_yield объекта yield
». Итак, у него новое имя объекта 9X_py generator
, как показано в Out[11]:
.
В заключение, как метафора 9X_generator для понимания:
return
иyield
- близнецыlist
иgenerator
- близнецы
- Это понятно, но одно из основных отличий заключается в том, что вы можете иметь несколько значений доходности в функции / методе. На этом аналогия полностью разрушается. Yield запоминает свое место в функции, поэтому в ...
Ответ #17
Ответ на вопрос: Что делает ключевое слово "yield"?
С точки зрения программирования итераторы 9X_iterator реализованы как thunks.
Чтобы реализовать итераторы, генераторы 9X_pythonista и пулы потоков для параллельного выполнения 9X_pythonic и т. д. в качестве преобразователей, используется 9X_generators messages sent to a closure object, у которого есть диспетчер, и dispatcher answers to "messages".
"next" - это сообщение, отправленное 9X_yield в закрытие, созданное вызовом «iter».
Есть много 9X_coroutine способов реализовать это вычисление. Я использовал 9X_coroutine мутацию, но можно выполнить такой вид вычислений 9X_listiterator без мутации, вернув текущее значение и следующий 9X_python выход (сделав его referential transparent). Racket использует последовательность 9X_pythonista преобразований исходной программы на некоторых 9X_python языках-посредниках, одно из таких переписываний 9X_coroutine приводит к преобразованию оператора yield 9X_generator на некотором языке с помощью более простых 9X_python-shell операторов.
Вот демонстрация того, как можно 9X_coroutine переписать yield, который использует структуру 9X_iterator R6RS, но семантика идентична семантике Python. Это 9X_listiterator та же модель вычислений, и требуется только 9X_listiterator изменение синтаксиса, чтобы переписать ее 9X_generators с использованием yield of Python.
Welcome to Racket v6.5.0.3. -> (define gen (lambda (l) (define yield (lambda () (if (null? l) 'END (let ((v (car l))) (set! l (cdr l)) v)))) (lambda(m) (case m ('yield (yield)) ('init (lambda (data) (set! l data) 'OK)))))) -> (define stream (gen '(1 2 3))) -> (stream 'yield) 1 -> (stream 'yield) 2 -> (stream 'yield) 3 -> (stream 'yield) 'END -> ((stream 'init) '(a b)) 'OK -> (stream 'yield) 'a -> (stream 'yield) 'b -> (stream 'yield) 'END -> (stream 'yield) 'END ->
Ответ #18
Ответ на вопрос: Что делает ключевое слово "yield"?
Вот несколько примеров Python того, как 9X_py на самом деле реализовать генераторы, как 9X_python-shell если бы Python не предоставлял для них синтаксический 9X_listiterator сахар:
Как генератор Python:
from itertools import islice def fib_gen(): a, b = 1, 1 while True: yield a a, b = b, a + b assert [1, 1, 2, 3, 5] == list(islice(fib_gen(), 5))
Использование лексических замыканий вместо генераторов
def ftake(fnext, last): return [fnext() for _ in xrange(last)] def fib_gen2(): #funky scope due to python2.x workaround #for python 3.x use nonlocal def _(): _.a, _.b = _.b, _.a + _.b return _.a _.a, _.b = 0, 1 return _ assert [1,1,2,3,5] == ftake(fib_gen2(), 5)
Использование замыканий объектов вместо генераторов (потому что ClosuresAndObjectsAreEquivalent)
class fib_gen3: def __init__(self): self.a, self.b = 1, 1 def __call__(self): r = self.a self.a, self.b = self.b, self.a + self.b return r assert [1,1,2,3,5] == ftake(fib_gen3(), 5)
Ответ #19
Ответ на вопрос: Что делает ключевое слово "yield"?
Я собирался опубликовать «прочтите 19-ю 9X_yield-keyword страницу книги Бизли« Python: Essential 9X_python-interpreter Reference »для быстрого описания генераторов», но 9X_py многие другие уже опубликовали хорошие описания.
Также 9X_iterators обратите внимание, что yield
может использоваться 9X_yield в сопрограммах как двойное средство их использования 9X_yield-keyword в функциях генератора. Хотя это не то же 9X_pythonic самое, что и ваш фрагмент кода, (yield)
можно использовать 9X_pythonic как выражение в функции. Когда вызывающий 9X_python-shell отправляет значение методу с помощью метода 9X_python-shell send()
, сопрограмма будет выполняться до тех пор, пока 9X_python-shell не встретится следующий оператор (yield)
.
Генераторы 9X_pythonic и сопрограммы - отличный способ настроить 9X_generator приложения, работающие с потоками данных. Я 9X_listiterator подумал, что стоит узнать о другом использовании 9X_yield-keyword оператора yield
в функциях.
Ответ #20
Ответ на вопрос: Что делает ключевое слово "yield"?
Вот простой пример:
def isPrimeNumber(n): print "isPrimeNumber({}) call".format(n) if n==1: return False for x in range(2,n): if n % x == 0: return False return True def primes (n=1): while(True): print "loop step ---------------- {}".format(n) if isPrimeNumber(n): yield n n += 1 for n in primes(): if n> 10:break print "wiriting result {}".format(n)
Вывод:
loop step ---------------- 1 isPrimeNumber(1) call loop step ---------------- 2 isPrimeNumber(2) call loop step ---------------- 3 isPrimeNumber(3) call wiriting result 3 loop step ---------------- 4 isPrimeNumber(4) call loop step ---------------- 5 isPrimeNumber(5) call wiriting result 5 loop step ---------------- 6 isPrimeNumber(6) call loop step ---------------- 7 isPrimeNumber(7) call wiriting result 7 loop step ---------------- 8 isPrimeNumber(8) call loop step ---------------- 9 isPrimeNumber(9) call loop step ---------------- 10 isPrimeNumber(10) call loop step ---------------- 11 isPrimeNumber(11) call
Я не разработчик 9X_python-shell Python, но мне кажется, что yield
содержит позицию 9X_python-shell потока программы, и следующий цикл начинается 9X_python с позиции "yield". Кажется, что он ждет 9X_pythonic в этой позиции, а непосредственно перед 9X_listiterator этим возвращает значение снаружи и в следующий 9X_yield раз продолжает работать.
Это интересная и 9X_pythonic приятная способность: D
Ответ #21
Ответ на вопрос: Что делает ключевое слово "yield"?
Вот мысленный образ того, что делает yield
.
Мне 9X_py нравится думать о потоке как о стеке (даже 9X_coroutine если он не реализован таким образом).
Когда 9X_yield вызывается обычная функция, она помещает 9X_yield-keyword свои локальные переменные в стек, выполняет 9X_iterators некоторые вычисления, затем очищает стек 9X_iterator и возвращается. Значения его локальных переменных 9X_pythonista больше никогда не видны.
С функцией yield
, когда 9X_generators ее код начинает выполняться (т.е. после 9X_python-interpreter вызова функции, возвращающей объект-генератор, чей 9X_iterators метод next()
затем вызывается), она аналогичным 9X_generator образом помещает свои локальные переменные 9X_iterator в стек и вычисляет некоторое время. Но затем, когда 9X_listiterator он попадает в оператор yield
, перед очисткой 9X_iterator своей части стека и возвратом он делает 9X_pythonic снимок своих локальных переменных и сохраняет 9X_yield их в объекте-генераторе. Он также записывает 9X_py текущее место в своем коде (т.е. конкретный 9X_python-interpreter оператор yield
).
Так что это своего рода замороженная 9X_pythonic функция, на которой висит генератор.
Когда 9X_python-interpreter next()
вызывается впоследствии, он извлекает принадлежность 9X_py функции в стек и повторно анимирует ее. Функция 9X_pythonista продолжает вычисление с того места, где 9X_py остановилась, не обращая внимания на тот 9X_iterators факт, что она только что провела целую вечность 9X_coroutine в холодном хранилище.
Сравните следующие 9X_coroutine примеры:
def normalFunction(): return if False: pass def yielderFunction(): return if False: yield 12
Когда мы вызываем вторую функцию, она 9X_listiterator ведет себя совсем не так, как первая. Оператор 9X_python yield
может быть недоступен, но если он где-то 9X_iterator присутствует, он меняет характер того, с 9X_iterator чем мы имеем дело.
>>> yielderFunction()
Вызов yielderFunction()
не запускает его 9X_yield код, а создает генератор из кода. (Возможно, стоит 9X_yield-keyword называть такие вещи префиксом yielder
для удобства 9X_generators чтения.)
>>> gen = yielderFunction() >>> dir(gen) ['__class__', ... '__iter__', #Returns gen itself, to make it work uniformly with containers ... #when given to a for loop. (Containers return an iterator instead.) 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', #The method that runs the function's body. 'send', 'throw']
В полях gi_code
и gi_frame
хранится замороженное 9X_yield состояние. Изучая их с помощью dir(..)
, мы можем 9X_python-interpreter подтвердить, что наша ментальная модель, приведенная 9X_pythonista выше, заслуживает доверия.
Ответ #22
Ответ на вопрос: Что делает ключевое слово "yield"?
Аналогия может помочь понять эту идею здесь:
Представьте, что 9X_iterator вы создали замечательную машину, способную 9X_pythonic генерировать тысячи и тысячи лампочек в 9X_python день. Машина производит эти лампочки в коробках 9X_yield с уникальным серийным номером. У вас недостаточно 9X_generator места для одновременного хранения всех этих 9X_coroutine лампочек (т. Е. Вы не можете успевать из-за 9X_python-interpreter ограничений по хранению), поэтому вы хотели 9X_generator бы настроить его для создания лампочек по 9X_generators запросу.
Генераторы Python не сильно отличаются 9X_listiterator от этой концепции.
Представьте, что у вас 9X_yield-keyword есть функция x
, которая генерирует уникальные 9X_generator серийные номера для ящиков. Очевидно, у 9X_yield-keyword вас может быть огромное количество таких 9X_python штрих-кодов, сгенерированных функцией. Более 9X_iterators разумным и эффективным вариантом является 9X_python-shell создание серийных номеров по запросу.
Машинный 9X_iterators код:
def barcode_generator(): serial_number = 10000 # Initial barcode while True: yield serial_number serial_number += 1 barcode = barcode_generator() while True: number_of_lightbulbs_to_generate = int(input("How many lightbulbs to generate? ")) barcodes = [next(barcode) for _ in range(number_of_lightbulbs_to_generate)] print(barcodes) # function_to_create_the_next_batch_of_lightbulbs(barcodes) produce_more = input("Produce more? [Y/n]: ") if produce_more == "n": break
Как видите, у нас есть автономная «функция» для 9X_python-shell генерации следующего уникального серийного 9X_python номера каждый раз. Эта функция возвращает 9X_yield-keyword генератор! Как видите, мы не вызываем функцию 9X_coroutine каждый раз, когда нам нужен новый серийный 9X_python-interpreter номер, но мы используем next()
, заданный генератору, для 9X_yield получения следующего серийного номера.
Вывод:
How many lightbulbs to generate? 5 [10000, 10001, 10002, 10003, 10004] Produce more? [Y/n]: y How many lightbulbs to generate? 6 [10005, 10006, 10007, 10008, 10009, 10010] Produce more? [Y/n]: y How many lightbulbs to generate? 7 [10011, 10012, 10013, 10014, 10015, 10016, 10017] Produce more? [Y/n]: n
Ответ #23
Ответ на вопрос: Что делает ключевое слово "yield"?
Простой пример, чтобы понять, что это такое: yield
def f123(): for _ in range(4): yield 1 yield 2 for i in f123(): print (i)
Результат:
1 2 1 2 1 2 1 2
9X_iterator
- @ user9074332, Вы правы, но написано в одну строчку ...
Ответ #24
Ответ на вопрос: Что делает ключевое слово "yield"?
Как следует из каждого ответа, yield
используется 9X_py для создания генератора последовательности. Он 9X_generators используется для динамической генерации 9X_coroutine некоторой последовательности. Например, при 9X_generators построчном чтении файла по сети вы можете 9X_pythonic использовать функцию yield
следующим образом:
def getNextLines(): while con.isOpen(): yield con.read()
Вы 9X_pythonic можете использовать его в своем коде следующим 9X_pythonic образом:
for line in getNextLines(): doSomeThing(line)
Попытка передать управление выполнением
Управление выполнением будет передано 9X_pythonista из getNextLines() в цикл for
при выполнении 9X_python yield. Таким образом, каждый раз, когда 9X_py вызывается getNextLines(), выполнение начинается 9X_py с того места, где оно было приостановлено 9X_yield в прошлый раз.
Короче говоря, функция со 9X_coroutine следующим кодом
def simpleYield(): yield "first time" yield "second time" yield "third time" yield "Now some useful value {}".format(12) for i in simpleYield(): print i
напечатает
"first time" "second time" "third time" "Now some useful value 12"
Ответ #25
Ответ на вопрос: Что делает ключевое слово "yield"?
(Мой ответ ниже говорит только с точки зрения 9X_pythonista использования генератора Python, а не с 9X_pythonic точки зрения underlying implementation of generator mechanism, который включает некоторые 9X_listiterator уловки манипулирования стеком и кучей.)
Когда 9X_pythonista yield
используется вместо return
в функции Python, эта 9X_coroutine функция превращается в нечто особенное, называемое 9X_generator generator function
. Эта функция вернет объект типа generator
. Ключевое слово yield
- это флаг, уведомляющий компилятор python о необходимости особого обращения с такой функцией. Обычные 9X_python-interpreter функции завершаются после того, как от него 9X_iterator будет возвращено какое-либо значение. Но 9X_generators с помощью компилятора функцию генератора 9X_coroutine можно рассматривать как возобновляемую. То есть контекст выполнения 9X_iterator будет восстановлен, и выполнение продолжится 9X_pythonic с последнего запуска. Пока вы явно не вызовете 9X_generators return, что вызовет исключение StopIteration
(которое 9X_yield-keyword также является частью протокола итератора) или 9X_yield не достигнет конца функции. Я нашел много 9X_iterators ссылок на generator
, но этот one из functional programming perspective
является наиболее 9X_pythonic усваиваемым.
(Теперь я хочу поговорить о 9X_pythonic причинах generator
и iterator
на основе моего собственного 9X_yield-keyword понимания. Надеюсь, это поможет вам понять 9X_generator существенную мотивацию итератора и генератора. Такая концепция 9X_py присутствует и в других языках, например 9X_iterator в C#.)
Насколько я понимаю, когда мы хотим 9X_coroutine обработать кучу данных, мы обычно сначала 9X_python где-то храним данные, а затем обрабатываем 9X_python-interpreter их по очереди. Но этот наивный подход проблематичен. Если 9X_py объем данных огромен, заранее хранить их 9X_python-interpreter целиком дорого. Итак, вместо того, чтобы хранить сам data
напрямую, почему бы не сохранить какой-то metadata
косвенно, то есть the logic how the data is computed
.
Есть два подхода к заключению 9X_python таких метаданных.
- При объектно-ориентированном подходе мы оборачиваем метаданные
as a class
. Это так называемыйiterator
, который реализует протокол итератора (то есть методы__next__()
и__iter__()
). Это также часто встречающийся iterator design pattern. - Функциональный подход, мы оборачиваем метаданные
as a function
. Это так называемыйgenerator function
. Но под капотом возвращенныйgenerator object
по-прежнемуIS-A
итератор, потому что он также реализует протокол итератора.
В любом случае создается 9X_python-shell итератор, то есть некий объект, который 9X_yield-keyword может предоставить вам нужные данные. Объектно-ориентированный 9X_iterator подход может быть немного сложным. В любом 9X_python-interpreter случае, какой использовать - решать вам.
Ответ #26
Ответ на вопрос: Что делает ключевое слово "yield"?
Таким образом, оператор yield
преобразует вашу 9X_python-interpreter функцию в фабрику, которая создает специальный 9X_iterator объект, называемый generator
, который обтекает тело 9X_listiterator вашей исходной функции. Когда generator
повторяется, он 9X_listiterator выполняет вашу функцию до тех пор, пока 9X_python-interpreter не достигнет следующего yield
, затем приостанавливает 9X_yield-keyword выполнение и оценивает значение, переданное 9X_pythonista в yield
. Он повторяет этот процесс на каждой 9X_pythonista итерации, пока путь выполнения не выйдет 9X_iterators из функции. Например,
def simple_generator(): yield 'one' yield 'two' yield 'three' for i in simple_generator(): print i
просто выводит
one two three
Мощность 9X_python-interpreter исходит от использования генератора с циклом, который 9X_python-shell вычисляет последовательность, генератор 9X_python выполняет цикл, останавливаясь каждый раз, чтобы 9X_python-shell «выдать» следующий результат вычисления, таким 9X_coroutine образом он вычисляет список на лету, преимущество 9X_iterators память, сэкономленная для особо больших 9X_iterators вычислений
Допустим, вы хотите создать свою 9X_iterator собственную функцию range
, которая генерирует 9X_yield повторяемый диапазон чисел, вы можете сделать 9X_generator это так,
def myRangeNaive(i): n = 0 range = [] while n < i: range.append(n) n = n + 1 return range
и используйте это так;
for i in myRangeNaive(10): print i
Но это неэффективно, потому 9X_listiterator что
- Вы создаете массив, который используете только один раз (это расходует память).
- Этот код фактически дважды перебирает этот массив! :(
К счастью, Гвидо и его команда были достаточно 9X_pythonista щедры, чтобы разработать генераторы, так 9X_yield что мы могли просто сделать это;
def myRangeSmart(i): n = 0 while n < i: yield n n = n + 1 return for i in myRangeSmart(10): print i
Теперь на 9X_generators каждой итерации функция в генераторе с именем 9X_iterator next()
выполняет функцию до тех пор, пока не достигнет 9X_python-interpreter оператора yield, в котором она останавливается 9X_yield и «возвращает» значение, или до конца функции. В 9X_listiterator этом случае при первом вызове next()
выполняется 9X_yield до оператора yield и yield 'n', при следующем 9X_listiterator вызове он выполнит оператор приращения, вернется 9X_python-shell к 'while', оценит его, и если истина, он 9X_generators остановится и снова выдаст 'n', так будет 9X_python-interpreter продолжаться до тех пор, пока условие while 9X_listiterator не вернет false и генератор не перейдет 9X_yield-keyword к концу функции.
Ответ #27
Ответ на вопрос: Что делает ключевое слово "yield"?
Доходность - это объект
return
в функции возвращает одно значение.
Если 9X_listiterator вы хотите, чтобы функция возвращала огромный набор значений, используйте yield
.
Что еще 9X_pythonista более важно, yield
- это барьер.
как барьер на языке 9X_py CUDA, он не передает управление, пока не 9X_python-interpreter получит завершено.
То есть он будет запускать 9X_iterators код в вашей функции с самого начала, пока 9X_python-shell не достигнет yield
. Затем он вернет первое значение 9X_python-shell цикла.
Затем каждый второй вызов будет запускать 9X_pythonic цикл, который вы написали в функции, еще 9X_coroutine раз, возвращая следующее значение до тех 9X_generators пор, пока не останется никакого значения 9X_iterator для возврата.
Ответ #28
Ответ на вопрос: Что делает ключевое слово "yield"?
Многие люди используют return
, а не yield
, но в некоторых 9X_generators случаях yield
может быть более эффективным и 9X_iterators с ним проще работать.
Вот пример, для которого 9X_iterator yield
определенно лучше всего:
return (в функции)
import random def return_dates(): dates = [] # With 'return' you need to create a list then return it for i in range(5): date = random.choice(["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th"]) dates.append(date) return dates
доходность (в 9X_pythonista работе)
def yield_dates(): for i in range(5): date = random.choice(["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th"]) yield date # 'yield' makes a generator automatically which works # in a similar way. This is much more efficient.
Вызов функций
dates_list = return_dates() print(dates_list) for i in dates_list: print(i) dates_generator = yield_dates() print(dates_generator) for i in dates_generator: print(i)
Обе функции делают одно и то же, но 9X_python yield
использует три строки вместо пяти и имеет 9X_py на одну переменную меньше, о чем нужно беспокоиться.
Это результат использования кода:
Как 9X_python видите, обе функции делают одно и то же. Единственная 9X_python разница в том, что return_dates()
предоставляет список, а 9X_python yield_dates()
- генератор.
Пример из реальной жизни - это 9X_iterators что-то вроде чтения файла построчно или 9X_yield если вы просто хотите создать генератор.
Ответ #29
Ответ на вопрос: Что делает ключевое слово "yield"?
Ключевое слово yield
просто собирает возвращаемые 9X_py результаты. Думайте о yield
как о return +=
Ответ #30
Ответ на вопрос: Что делает ключевое слово "yield"?
yield
похож на возвращаемый элемент для функции. Разница 9X_listiterator в том, что элемент yield
превращает функцию в 9X_pythonista генератор. Генератор ведет себя точно так 9X_yield-keyword же, как функция, пока что-то не «уступит». Генератор 9X_coroutine останавливается до следующего вызова и продолжает 9X_pythonista работу с той же точки, с которой он был 9X_iterator запущен. Вы можете получить последовательность 9X_listiterator всех "полученных" значений в одном, вызвав 9X_yield-keyword list(generator())
.
Ответ #31
Ответ на вопрос: Что делает ключевое слово "yield"?
Еще один TL; DR
Итератор в списке: next()
возвращает следующий элемент 9X_py списка
Генератор итератора: next()
будет вычислять следующий элемент 9X_pythonic на лету (выполнить код)
Вы можете увидеть 9X_python-shell yield / generator как способ вручную запустить 9X_iterators поток управления извне (например, продолжить цикл на один 9X_iterator шаг), вызвав next
, каким бы сложным ни был поток.
Примечание. Генератор 9X_iterator НЕ является нормальной функцией. Он запоминает 9X_python предыдущее состояние как локальные переменные 9X_iterator (стек). См. Другие ответы или статьи для 9X_listiterator подробного объяснения. Генератор можно повторить только один раз. Вы 9X_yield-keyword могли бы обойтись без yield
, но это было бы не 9X_coroutine так хорошо, поэтому его можно считать «очень 9X_iterator приятным» языковым сахаром.
Ответ #32
Ответ на вопрос: Что делает ключевое слово "yield"?
Вот простой подход, основанный на yield
, для 9X_yield вычисления ряда Фибоначчи, объясненный:
def fib(limit=50): a, b = 0, 1 for i in range(limit): yield b a, b = b, a+b
Когда 9X_yield-keyword вы вводите это в свой REPL, а затем пытаетесь 9X_iterators вызвать его, вы получите загадочный результат:
>>> fib()
Это 9X_python-interpreter связано с тем, что наличие yield
сигнализирует 9X_yield Python о том, что вы хотите создать генератор, то 9X_listiterator есть объект, который генерирует значения 9X_yield по запросу.
Итак, как вы генерируете эти 9X_iterators значения? Это можно сделать либо напрямую, используя 9X_yield-keyword встроенную функцию next
, либо косвенно, передав 9X_pythonic ее в конструкцию, которая потребляет значения.
Используя 9X_generators встроенную функцию next()
, вы напрямую вызываете 9X_iterator .next
/ __next__
, заставляя генератор генерировать значение:
>>> g = fib() >>> next(g) 1 >>> next(g) 1 >>> next(g) 2 >>> next(g) 3 >>> next(g) 5
Косвенно, если 9X_iterator вы предоставите fib
циклу for
, инициализатору 9X_yield list
, инициализатору tuple
или чему-либо еще, ожидающему 9X_yield объект, который генерирует / производит 9X_pythonista значения, вы "потребляете" генератор до 9X_python тех пор, пока он не перестанет генерировать 9X_iterator значения (и он не вернется):
results = [] for i in fib(30): # consumes fib results.append(i) # can also be accomplished with results = list(fib(30)) # consumes fib
Аналогично с 9X_yield-keyword инициализатором tuple
:
>>> tuple(fib(5)) # consumes fib (1, 1, 2, 3, 5)
Генератор отличается от 9X_python-shell функции тем, что он ленив. Это достигается 9X_yield-keyword за счет сохранения своего локального состояния 9X_yield-keyword и возможности возобновления работы в любое 9X_yield время.
Когда вы впервые вызываете fib
, вызывая 9X_pythonista его:
f = fib()
Python компилирует функцию, встречает 9X_python-interpreter ключевое слово yield
и просто возвращает вам 9X_python-interpreter объект-генератор. Кажется, не очень полезно.
Когда 9X_generator вы затем запрашиваете, он генерирует первое 9X_python-shell значение, прямо или косвенно, он выполняет 9X_iterator все найденные операторы, пока не встречает 9X_pythonic yield
, затем возвращает значение, которое вы 9X_yield указали в yield
, и приостанавливает работу. В 9X_iterators качестве примера, который лучше демонстрирует 9X_py это, давайте воспользуемся некоторыми вызовами 9X_python-interpreter print
(замените на print "text"
, если на Python 2):
def yielder(value): """ This is an infinite generator. Only use next on it """ while 1: print("I'm going to generate the value for you") print("Then I'll pause for a while") yield value print("Let's go through it again.")
Теперь 9X_coroutine введите REPL:
>>> gen = yielder("Hello, yield!")
у вас есть объект-генератор, ожидающий 9X_yield-keyword команды для генерации значения. Используйте 9X_yield-keyword next
и посмотрите, что будет напечатано:
>>> next(gen) # runs until it finds a yield I'm going to generate the value for you Then I'll pause for a while 'Hello, yield!'
Результаты 9X_generators без кавычек - это то, что печатается. Цитируемый 9X_generator результат - это то, что возвращается из 9X_pythonista yield
. Позвоните next
еще раз сейчас:
>>> next(gen) # continues from yield and runs again Let's go through it again. I'm going to generate the value for you Then I'll pause for a while 'Hello, yield!'
Генератор запоминает, что 9X_python он был приостановлен на yield value
, и возобновляет 9X_coroutine работу с этого момента. Следующее сообщение 9X_pythonista печатается, и снова выполняется поиск оператора 9X_iterators yield
, чтобы приостановить его (из-за цикла while
).
Ответ #33
Ответ на вопрос: Что делает ключевое слово "yield"?
yield аналогичен доходу. Разница в следующем:
yield делает 9X_iterators функцию итерируемой (в следующем примере 9X_generators функция primes(n = 1)
становится итерируемой).
По сути, это 9X_generators означает, что при следующем вызове функции 9X_pythonista она продолжится с того места, где была оставлена 9X_yield (то есть после строки yield expression
).
def isprime(n): if n == 1: return False for x in range(2, n): if n % x == 0: return False else: return True def primes(n = 1): while(True): if isprime(n): yield n n += 1 for n in primes(): if n > 100: break print(n)
В приведенном 9X_yield выше примере, если isprime(n)
истинно, будет возвращено 9X_python-shell простое число. В следующей итерации он будет 9X_iterators продолжен со следующей строки
n += 1
Ответ #34
Ответ на вопрос: Что делает ключевое слово "yield"?
В Python generators
(особый тип iterators
) используются для 9X_python-shell генерации серий значений, а ключевое слово 9X_python-shell yield
аналогично ключевому слову return
функций генератора.
Еще одна интересная особенность ключевого слова yield
- это сохранение state
функции генератора.
Итак, мы 9X_iterator можем устанавливать для number
другое значение 9X_python-interpreter каждый раз, когда generator
дает результат.
Вот пример:
def getPrimes(number): while True: if isPrime(number): number = yield number # a miracle occurs here number += 1 def printSuccessivePrimes(iterations, base=10): primeGenerator = getPrimes(base) primeGenerator.send(None) for power in range(iterations): print(primeGenerator.send(base ** power))
Ответ #35
Ответ на вопрос: Что делает ключевое слово "yield"?
yield
что-то дает. Как будто кто-то просит вас 9X_python-interpreter сделать 5 кексов. Если вы закончили хотя 9X_yield бы с одним кексом, вы можете дать им поесть, пока 9X_python-interpreter готовите другие пирожные.
In [4]: def make_cake(numbers): ...: for i in range(numbers): ...: yield 'Cake {}'.format(i) ...: In [5]: factory = make_cake(5)
Здесь factory
называется 9X_py генератором, который делает вам пирожные. Если 9X_py вы вызовете make_function
, вы получите генератор вместо 9X_generators запуска этой функции. Это потому, что когда 9X_iterator ключевое слово yield
присутствует в функции, оно 9X_python-interpreter становится генератором.
In [7]: next(factory) Out[7]: 'Cake 0' In [8]: next(factory) Out[8]: 'Cake 1' In [9]: next(factory) Out[9]: 'Cake 2' In [10]: next(factory) Out[10]: 'Cake 3' In [11]: next(factory) Out[11]: 'Cake 4'
Они съели все пирожные, но 9X_python-shell просят еще один.
In [12]: next(factory) --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) in ----> 1 next(factory) StopIteration:
и им говорят перестать спрашивать 9X_yield больше. Итак, как только вы съели генератор, вы 9X_generators закончите с ним. Вам нужно снова вызвать 9X_generator make_cake
, если вы хотите больше тортов. Это все 9X_pythonista равно, что разместить очередной заказ на 9X_pythonista кексы.
In [13]: factory = make_cake(3) In [14]: for cake in factory: ...: print(cake) ...: Cake 0 Cake 1 Cake 2
Вы также можете использовать цикл 9X_generators for с генератором, подобным приведенному 9X_yield-keyword выше.
Еще один пример: допустим, вам нужен 9X_yield-keyword случайный пароль, когда вы его запрашиваете.
In [22]: import random In [23]: import string In [24]: def random_password_generator(): ...: while True: ...: yield ''.join([random.choice(string.ascii_letters) for _ in range(8)]) ...: In [25]: rpg = random_password_generator() In [26]: for i in range(3): ...: print(next(rpg)) ...: FXpUBhhH DdUDHoHn dvtebEqG In [27]: next(rpg) Out[27]: 'mJbYRMNo'
Здесь 9X_yield rpg
- генератор, который может генерировать 9X_listiterator бесконечное количество случайных паролей. Таким 9X_coroutine образом, мы также можем сказать, что генераторы 9X_py полезны, когда мы не знаем длины последовательности, в 9X_yield-keyword отличие от списка, который имеет конечное 9X_pythonista число элементов.
Ответ #36
Ответ на вопрос: Что делает ключевое слово "yield"?
Все ответы здесь прекрасны; но только один 9X_iterators из них (получивший наибольшее количество 9X_py голосов) касается того, как работает ваш код. Другие относятся к генераторам в 9X_python-interpreter целом и к тому, как они работают.
Поэтому 9X_yield я не буду повторять, что такое генераторы 9X_python-interpreter и что делают урожаи; Я думаю, что на них 9X_generators есть отличные существующие ответы. Однако, потратив 9X_generators несколько часов на попытки понять код, похожий 9X_generators на ваш, я расскажу, как он работает.
Ваш 9X_pythonista код проходит через двоичную древовидную 9X_pythonic структуру. Возьмем, к примеру, это дерево:
5 / \ 3 6 / \ \ 1 4 8
И 9X_python еще одна более простая реализация обхода 9X_yield дерева двоичного поиска:
class Node(object): .. def __iter__(self): if self.has_left_child(): for child in self.left: yield child yield self.val if self.has_right_child(): for child in self.right: yield child
Код выполнения находится 9X_generator в объекте Tree
, который реализует __iter__
следующим 9X_generator образом:
def __iter__(self): class EmptyIter(): def next(self): raise StopIteration if self.root: return self.root.__iter__() return EmptyIter()
Оператор while candidates
можно заменить на for element in tree
; Python 9X_listiterator переведет это на
it = iter(TreeObj) # returns iter(self.root) which calls self.root.__iter__() for element in it: .. process element ..
Поскольку функция Node.__iter__
является 9X_iterators генератором, код внутри нее выполняется на каждой 9X_yield итерации. Таким образом, казнь будет выглядеть 9X_yield так:
- корневой элемент является первым; проверьте, остались ли дочерние элементы, и
for
выполнит итерацию по ним (назовем его it1, потому что это первый объект итератора) - у него есть дочерний элемент, поэтому выполняется
for
.for child in self.left
создает новый итератор изself.left
, который сам является объектом узла (it2) - Та же логика, что и 2, но создается новый
iterator
(it3) - Теперь мы достигли левого конца дерева.
it3
не имеет левых дочерних элементов, поэтому он продолжается иyield self.value
- При следующем вызове
next(it3)
он вызываетStopIteration
и существует, поскольку у него нет правильных дочерних элементов (он достигает конца функции, ничего не возвращая). it1
иit2
все еще активны - они не исчерпаны, и вызовnext(it2)
приведет к получению значений, а не к увеличениюStopIteration
- Теперь мы вернулись к контексту
it2
и вызываемnext(it2)
, который продолжается с того места, где он остановился: сразу после оператораyield child
. Поскольку у него больше нет левых дочерних элементов, он продолжает работу и возвращает егоself.val
.
Уловка здесь в том, что каждая итерация 9X_iterators создает под-итераторы для обхода дерева и сохраняет состояние 9X_pythonic текущего итератора. Достигнув конца, он 9X_yield возвращается по стеку, и значения возвращаются 9X_generators в правильном порядке (сначала возвращается 9X_python-interpreter наименьшее значение).
В вашем примере кода 9X_python-shell было сделано нечто похожее с использованием 9X_yield другой техники: он заполнил одноэлементный список для каждого 9X_python-interpreter дочернего элемента, затем на следующей итерации 9X_pythonic он вытащил его и запустил код функции для 9X_pythonic текущего объекта ( отсюда self
).
Надеюсь, это 9X_generator немного повлияло на эту легендарную тему. Я 9X_generator потратил несколько часов на рисование этого 9X_generator процесса, чтобы понять его.
Ответ #37
Ответ на вопрос: Что делает ключевое слово "yield"?
ключевое слово yield в python используется 9X_py для выхода из кода без нарушения состояния 9X_pythonic локальной переменной и при повторном вызове 9X_python-shell функции выполнение начинается с последней 9X_yield точки, где мы оставили код.
Пример ниже демонстрирует 9X_iterator его работу:
def counter(): x=2 while x < 5: yield x x += 1 print("Initial value of x: ", counter()) x=2 x=x+1 for y in counter(): print(y)
Приведенный выше код генерирует 9X_generators следующий вывод:
Начальное значение x: <�счетчик 9X_yield объектов генератора по адресу 0x7f0263020ac0>
2
3
4
- @ pippo1980 это просто для того, чтобы показать, что на `x` ...
Ответ #38
Ответ на вопрос: Что делает ключевое слово "yield"?
Может также отправлять данные обратно в генератор!
Действительно, как объясняется здесь во 9X_yield многих ответах, использование yield
создает generator
.
Вы 9X_python-shell можете использовать ключевое слово yield
для 9X_coroutine отправки данных обратно в "живой" генератор.
Пример:
Допустим, у нас есть метод, который переводит 9X_pythonic с английского на какой-то другой язык. И 9X_iterator вначале он делает что-то тяжелое, и это 9X_pythonic нужно сделать один раз. Мы хотим, чтобы 9X_pythonista этот метод работал вечно (не знаю почему 9X_python-shell .. :)) и получал слова слова для перевода.
def translator(): # load all the words in English language and the translation to 'other lang' my_words_dict = {'hello': 'hello in other language', 'dog': 'dog in other language'} while True: word = (yield) yield my_words_dict.get(word, 'Unknown word...')
Бег:
my_words_translator = translator() next(my_words_translator) print(my_words_translator.send('dog')) next(my_words_translator) print(my_words_translator.send('cat'))
напечатает:
dog in other language Unknown word...
Подведем итоги:
используйте 9X_coroutine метод send
внутри генератора для отправки данных 9X_yield обратно в генератор. Для этого используется 9X_python (yield)
.
Ответ #39
Ответ на вопрос: Что делает ключевое слово "yield"?
yield в python похож на оператор return, за 9X_iterator исключением некоторых отличий. Если из функции 9X_generators должно быть возвращено несколько значений, оператор 9X_pythonic return вернет все значения в виде списка, и 9X_listiterator он должен быть сохранен в памяти в блоке 9X_pythonic вызывающего. Но что, если мы не хотим использовать 9X_listiterator дополнительную память? Вместо этого мы хотим 9X_iterator получить значение от функции, когда оно 9X_python-shell нам нужно. Вот где приходит доходность. Рассмотрим 9X_generators следующую функцию: -
def fun(): yield 1 yield 2 yield 3
И вызывающий абонент: -
def caller(): print ('First value printing') print (fun()) print ('Second value printing') print (fun()) print ('Third value printing') print (fun())
Приведенный 9X_yield выше сегмент кода (вызывающая функция) при 9X_py вызове выводит: -
First value printing 1 Second value printing 2 Third value printing 3
Как видно из вышеизложенного, yield 9X_pythonic возвращает значение вызывающей стороне, но 9X_listiterator когда функция вызывается снова, она начинается 9X_iterators не с первого оператора, а с оператора сразу 9X_py после yield. В приведенном выше примере 9X_iterators была напечатана «Печать первого значения» и 9X_generator была вызвана функция. 1 был возвращен и 9X_yield напечатан. Затем была напечатана «печать 9X_python-interpreter второго значения» и снова был вызван fun(). Вместо 9X_coroutine того, чтобы печатать 1 (первый оператор), он 9X_yield-keyword вернул 2, т.е. оператор сразу после yield 9X_generators 1. Тот же процесс повторяется и дальше.
Ответ #40
Ответ на вопрос: Что делает ключевое слово "yield"?
Простыми словами
Оператор yield приостанавливает выполнение 9X_generator функции и отправляет значение обратно вызывающей 9X_coroutine стороне, но сохраняет состояние, достаточное 9X_generators для возобновления функции с того места, где 9X_py она была остановлена. При возобновлении 9X_generator функция продолжает выполнение сразу после 9X_pythonista последнего выполнения yield. Это позволяет 9X_yield его коду создавать серию значений с течением 9X_listiterator времени, а не вычислять их сразу и отправлять 9X_generator обратно в виде списка.
Давайте посмотрим на примере:
# A Simple Python program to demonstrate working # of yield # A generator function that yields 1 for the first time, # 2 second time and 3 third time def simpleGeneratorFun(): yield 1 yield 2 yield 3
Код драйвера для проверки вышеуказанной функции генератора
for value in simpleGeneratorFun(): print(value) Output: 1 2 3
Return отправляет 9X_coroutine указанное значение обратно вызывающей стороне, тогда 9X_yield-keyword как Yield может генерировать последовательность 9X_pythonista значений. Нам следует использовать yield, когда 9X_py мы хотим перебрать последовательность, но 9X_coroutine не хотим сохранять всю последовательность 9X_yield в памяти.
Доходность используются в генераторах Python. Функция 9X_python генератора определяется как обычная функция, но 9X_pythonic всякий раз, когда ей нужно сгенерировать 9X_yield значение, она делает это с ключевым словом 9X_generator yield, а не return. Если тело def содержит 9X_listiterator yield, функция автоматически становится 9X_pythonic функцией-генератором.
Ответ #41
Ответ на вопрос: Что делает ключевое слово "yield"?
Простой ответ
Когда функция содержит хотя бы один оператор 9X_iterator yield
, функция автоматически становится функцией 9X_python-shell генератора. Когда вы вызываете функцию генератора, python 9X_pythonic выполняет код в функции генератора до тех 9X_generator пор, пока не появится оператор yield
. Оператор 9X_generator yield
замораживает функцию со всеми ее внутренними 9X_yield состояниями. Когда вы снова вызываете функцию 9X_generators генератора, python продолжает выполнение 9X_yield кода в функции генератора из замороженного 9X_generators положения, пока оператор yield
не будет повторяться 9X_coroutine снова и снова. Функция генератора выполняет 9X_yield код до тех пор, пока функция генератора 9X_yield не завершится без оператора yield
.
Тест
Создайте список 9X_coroutine и верните его:
def my_range(n): my_list = [] i = 0 while i < n: my_list.append(i) i += 1 return my_list @profile def function(): my_sum = 0 my_values = my_range(1000000) for my_value in my_values: my_sum += my_value function()
Результаты с:
Total time: 1.07901 s Timer unit: 1e-06 s Line # Hits Time Per Hit % Time Line Contents ============================================================== 9 @profile 10 def function(): 11 1 1.1 1.1 0.0 my_sum = 0 12 1 494875.0 494875.0 45.9 my_values = my_range(1000000) 13 1000001 262842.1 0.3 24.4 for my_value in my_values: 14 1000000 321289.8 0.3 29.8 my_sum += my_value Line # Mem usage Increment Occurences Line Contents ============================================================ 9 40.168 MiB 40.168 MiB 1 @profile 10 def function(): 11 40.168 MiB 0.000 MiB 1 my_sum = 0 12 78.914 MiB 38.746 MiB 1 my_values = my_range(1000000) 13 78.941 MiB 0.012 MiB 1000001 for my_value in my_values: 14 78.941 MiB 0.016 MiB 1000000 my_sum += my_value
Генерация значений 9X_listiterator на лету:
def my_range(n): i = 0 while i < n: yield i i += 1 @profile def function(): my_sum = 0 for my_value in my_range(1000000): my_sum += my_value function()
Результаты с:
Total time: 1.24841 s Timer unit: 1e-06 s Line # Hits Time Per Hit % Time Line Contents ============================================================== 7 @profile 8 def function(): 9 1 1.1 1.1 0.0 my_sum = 0 10 11 1000001 895617.3 0.9 71.7 for my_value in my_range(1000000): 12 1000000 352793.7 0.4 28.3 my_sum += my_value Line # Mem usage Increment Occurences Line Contents ============================================================ 7 40.168 MiB 40.168 MiB 1 @profile 8 def function(): 9 40.168 MiB 0.000 MiB 1 my_sum = 0 10 11 40.203 MiB 0.016 MiB 1000001 for my_value in my_range(1000000): 12 40.203 MiB 0.020 MiB 1000000 my_sum += my_value
Резюме
Для выполнения функции 9X_yield генератора требуется немного больше времени, чем 9X_python-shell функции, которая возвращает список, но использует 9X_python-shell гораздо меньше памяти.
Ответ #42
Ответ на вопрос: Что делает ключевое слово "yield"?
Простой пример использования:
>>> def foo(): yield 100 yield 20 yield 3 >>> for i in foo(): print(i) 100 20 3 >>>
Как это работает: при 9X_iterators вызове функция немедленно возвращает объект. Объект 9X_coroutine можно передать в функцию next(). Всякий 9X_generator раз, когда вызывается функция next(), ваша 9X_generator функция выполняется до следующего yield 9X_python и предоставляет возвращаемое значение для 9X_generator функции next().
Под капотом цикл for распознает, что 9X_pythonista объект является объектом-генератором, и 9X_listiterator использует next() для получения следующего 9X_yield значения.
В некоторых языках, таких как ES6 9X_python-interpreter и выше, это реализовано немного по-другому, поэтому 9X_iterator next является функцией-членом объекта-генератора, и 9X_yield вы можете передавать значения от вызывающего 9X_python-interpreter каждый раз, когда он получает следующее 9X_pythonic значение. Итак, если результат является 9X_generators генератором, вы можете сделать что-то вроде 9X_yield-keyword y = result.next (555), а программа, выдающая 9X_yield значения, могла бы сказать что-то вроде 9X_yield z = yield 999. Значение y будет 999, которое 9X_iterator затем будет получено из yield, и значение 9X_generators z будет 555, что дает доход от следующего. Python, похоже, этого 9X_coroutine не делает (пока? Может, когда-нибудь?)
Ответ #43
Ответ на вопрос: Что делает ключевое слово "yield"?
Обычно он используется для создания итератора 9X_coroutine вне функции. Подумайте, что «yield» - это 9X_generators добавление() к вашей функции, а ваша функция 9X_listiterator - как массив. И если определенные критерии 9X_generators соответствуют, вы можете добавить это значение 9X_yield-keyword в свою функцию, чтобы сделать ее итератором.
arr=[] if 2>0: arr.append(2) def func(): if 2>0: yield 2
результат 9X_pythonista будет одинаковым для обоих.
Основное преимущество 9X_pythonista использования yield - создание итераторов. Итераторы 9X_python-interpreter не вычисляют значение каждого элемента при 9X_iterator создании экземпляра. Они вычисляют это только 9X_yield-keyword тогда, когда вы об этом просите. Это называется 9X_python ленивым вычислением.
Ответ #44
Ответ на вопрос: Что делает ключевое слово "yield"?
Функция - возвращает.
Генератор - доходность 9X_listiterator (содержит одну или несколько доходностей 9X_py и ноль или несколько доходностей).
names = ['Sam', 'Sarah', 'Thomas', 'James'] # Using function def greet(name) : return f'Hi, my name is {name}.' for each_name in names: print(greet(each_name)) # Output: >>>Hi, my name is Sam. >>>Hi, my name is Sarah. >>>Hi, my name is Thomas. >>>Hi, my name is James. # using generator def greetings(names) : for each_name in names: yield f'Hi, my name is {each_name}.' for greet_name in greetings(names): print (greet_name) # Output: >>>Hi, my name is Sam. >>>Hi, my name is Sarah. >>>Hi, my name is Thomas. >>>Hi, my name is James.
Генератор 9X_yield выглядит как функция, но ведет себя как 9X_pythonic итератор.
Генератор продолжает выполнение 9X_python-interpreter с того места, где он был прекращен (или 9X_pythonista передан). При возобновлении функция продолжает 9X_py выполнение сразу после последнего прогона 9X_pythonic yield. Это позволяет его коду создавать 9X_generators серию значений с течением времени, а не 9X_coroutine вычислять их все сразу и отправлять обратно 9X_pythonista в виде списка.
def function(): yield 1 # return this first yield 2 # start continue from here (yield don't execute above code once executed) yield 3 # give this at last (yield don't execute above code once executed) for processed_data in function(): print(processed_data) #Output: >>>1 >>>2 >>>3
Примечание. Выход не должен 9X_generator входить в конструкцию try ... finally.
Ответ #45
Ответ на вопрос: Что делает ключевое слово "yield"?
Ключевое слово yield
используется в перечислении/итерации, когда 9X_python ожидается, что функция вернет более одного 9X_yield вывода. Я хочу привести этот очень простой 9X_coroutine пример:
def getNumber(): for r in range(1,10): return r
Приведенная выше функция вернет только 9X_generators 1, даже если она вызывается несколько раз. Теперь, если 9X_yield мы заменим return
на yield
как:
def getNumber(): for r in range(1,10): yield r
Он вернет 1 при первом 9X_pythonic вызове 2 при повторном вызове, затем 3, 4 и 9X_python будет увеличиваться до 10.
Ответ #46
Ответ на вопрос: Что делает ключевое слово "yield"?
Генераторы позволяют сразу получать отдельные 9X_generators обработанные элементы (без необходимости 9X_generator ждать обработки всей коллекции). Это показано 9X_pythonista в примере ниже.
import time def get_gen(): for i in range(10): yield i time.sleep(1) def get_list(): ret = [] for i in range(10): ret.append(i) time.sleep(1) return ret start_time = time.time() print('get_gen iteration (individual results come immediately)') for i in get_gen(): print(f'result arrived after: {time.time() - start_time:.0f} seconds') print() start_time = time.time() print('get_list iteration (results come all at once)') for i in get_list(): print(f'result arrived after: {time.time() - start_time:.0f} seconds')
get_gen iteration (individual results come immediately) result arrived after: 0 seconds result arrived after: 1 seconds result arrived after: 2 seconds result arrived after: 3 seconds result arrived after: 4 seconds result arrived after: 5 seconds result arrived after: 6 seconds result arrived after: 7 seconds result arrived after: 8 seconds result arrived after: 9 seconds get_list iteration (results come all at once) result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds result arrived after: 10 seconds
Ответ #47
Ответ на вопрос: Что делает ключевое слово "yield"?
Ключевые моменты
-
grammar for Python использует наличие ключевого слова
yield
для 9X_yield-keyword создания функции, которая возвращает generator. -
Генератор 9X_listiterator — это своего рода iterator, который является основным 9X_python-shell способом создания цикла в Python.
-
Генератор 9X_iterator — это, по существу, возобновляемая функция. В 9X_pythonic отличие от
return
, которое возвращает значение 9X_python-shell и завершает функцию, ключевое словоyield
возвращает 9X_pythonista значение и приостанавливает функцию. -
Когда 9X_python-shell
next(g)
вызывается для генератора, функция возобновляет 9X_yield-keyword выполнение с того места, где оно было остановлено. -
Только 9X_iterators когда функция сталкивается с явным или подразумеваемым 9X_yield-keyword
return
, она фактически завершается.
Техника написания и понимания генераторов
Простой способ 9X_python-shell понять генераторы и подумать о них — написать 9X_coroutine обычную функцию с print()
вместо yield
:
def f(n): for x in range(n): print(x) print(x * 10)
Смотрите, что 9X_iterator выдает:
>>> f(3) 0 0 1 10 2 2
Когда эта функция понятна, замените 9X_pythonista yield
на print
, чтобы получить генератор, который 9X_yield-keyword выдает те же значения:
def f(n): for x in range(n): yield x yield x * 10
Что дает:
>>> list(f(3)) [0, 0, 1, 10, 2, 20]
Протокол итератора
Ответ на 9X_iterator вопрос "что делает yield" может 9X_pythonista быть коротким и простым, но он является 9X_python частью большого мира, так называемого "итераторного 9X_pythonic протокола".
На стороне отправителя протокола 9X_pythonista итератора есть два соответствующих типа 9X_python-interpreter объектов. iterables — это то, что вы можете перебирать. А 9X_generators итераторы — это объекты, отслеживающие состояние 9X_yield цикла.
На стороне потребителя протокола итератора 9X_listiterator мы вызываем iter() для итерируемого объекта, чтобы 9X_generators получить итератор. Затем мы вызываем next() на 9X_iterators итераторе, чтобы получить значения из итератора. Когда 9X_py данных больше нет, возникает исключение 9X_python-interpreter StopIteration:
>>> s = [10, 20, 30] # The list is the "iterable" >>> it = iter(s) # This is the "iterator" >>> next(it) # Gets values out of an iterator 10 >>> next(it) 20 >>> next(it) 30 >>> next(it) Traceback (most recent call last): ... StopIteration
Чтобы упростить нам задачу, циклы for вызывают 9X_python-shell iter и next от нашего имени:
>>> for x in s: ... print(x) ... 10 20 30
Обо всем этом 9X_generators можно написать книгу, но это ключевые моменты. Когда 9X_listiterator я преподаю курсы Python, я обнаружил, что 9X_iterator это минимальное объяснение, достаточное 9X_python-interpreter для понимания и немедленного начала его 9X_generator использования. В частности, способ написать 9X_yield-keyword функцию с print
, протестировать ее и затем преобразовать 9X_python в yield
, похоже, хорошо работает с программистами 9X_iterators Python любого уровня.
Ответ #48
Ответ на вопрос: Что делает ключевое слово "yield"?
Чтобы понять его функцию доходности, нужно 9X_yield-keyword понять, что такое генератор. Более того, прежде 9X_python-shell чем разбираться в генераторах, вы должны 9X_generators понять iterables. Повторяемый: повторяемый Чтобы 9X_python создать список, вам, естественно, нужно 9X_python иметь возможность читать каждый элемент 9X_python-interpreter по одному. Процесс чтения его элементов 9X_pythonista один за другим называется итерацией:
>>> mylist = [1, 2, 3] >>> for i in mylist: ... print(i) 1 2 3
mylist 9X_yield является итерируемым. Когда вы используете 9X_pythonista списки, вы создаете список и, следовательно, повторяемый:
>>> mylist = [x*x for x in range(3)] >>> for i in mylist: ... print(i) 0 1 4
Все 9X_listiterator структуры данных, которые можно использовать 9X_python-interpreter для... в..., являются итерируемыми; списки, строки, файлы...
Эти 9X_pythonista итерируемые методы удобны тем, что их можно 9X_listiterator читать по желанию, но вы храните все значения 9X_python-interpreter в памяти, что не всегда желательно, когда 9X_yield у вас много значений. Генератор: генератор Генератор 9X_coroutine также является своего рода итератором, особым 9X_python-interpreter видом итерации, которую можно повторить 9X_listiterator только один раз. Генератор не хранит все 9X_py значения в памяти, а генерирует значения 9X_generators на лету:
генератор: генератор, генератор, генератор 9X_python вырабатывает электроэнергию, но не хранит 9X_coroutine энергию ;)
>>> mygenerator = (x*x for x in range(3)) >>> for i in mygenerator: ... print(i) 0 1 4
Пока () используется вместо [], понимание 9X_iterator списка становится пониманием генератора. Однако, поскольку 9X_iterators генератор можно использовать только один 9X_listiterator раз, вы не можете выполнить для i в mygenerator 9X_generator второй раз: генератор вычисляет 0, затем 9X_generator отбрасывает его, затем вычисляет 1 и в последний 9X_yield раз вычисляет 4. Типичный черный слепой 9X_listiterator ломает кукурузу .
Ключевое слово yield используется 9X_py так же, как и return, за исключением того, что 9X_listiterator функция возвращает генератор.
>>> def createGenerator(): ... mylist = range(3) ... for i in mylist: ... yield i*i ... >>> mygenerator = createGenerator() >>> print(mygenerator) >>> for i in mygenerator: ... print(i) 0 1 4
Сам по себе 9X_pythonista этот пример бесполезен, но когда вам нужна 9X_py функция для возврата большого количества 9X_iterator значений и нужно прочитать ее только один 9X_python-interpreter раз, использование yield становится удобным.
Чтобы 9X_python освоить yield, нужно четко понимать, что 9X_pythonic при вызове функции код, написанный в теле 9X_py функции, не будет выполняться. Функция возвращает 9X_yield-keyword только объект генератора. Новичков это может 9X_yield-keyword смутить.
Во-вторых, поймите, что код будет 9X_yield-keyword продолжаться с того места, где он остановился 9X_py каждый раз, когда используется генератор.
Самое 9X_iterator сложное сейчас это:
При первом вызове объекта-генератора, созданного 9X_python из вашей функции, он будет запускать код 9X_python-shell в функции с самого начала, пока не достигнет 9X_yield-keyword yield, а затем вернет первое значение цикла. Затем 9X_generator каждый последующий вызов будет запускать 9X_coroutine следующую итерацию цикла, который вы написали 9X_python-shell в функции, и возвращать следующее значение. Это 9X_coroutine будет продолжаться до тех пор, пока генератор 9X_generator не будет считаться пустым, что приводит 9X_py к отсутствию попадания во время выполнения 9X_yield-keyword функции. Это может быть из-за того, что 9X_coroutine цикл закончился, или из-за того, что вас 9X_iterators больше не устраивает "if/else".
Личное понимание, я 9X_iterators надеюсь помочь вам!
Ответ #49
Ответ на вопрос: Что делает ключевое слово "yield"?
yield
используется для создания generator
. Думайте о генераторе 9X_yield-keyword как об итераторе, который дает вам ценность 9X_iterator на каждой итерации. Когда вы используете 9X_pythonic yield в цикле, вы получаете объект генератора, который 9X_pythonic вы можете использовать для получения элементов 9X_generators из цикла итеративным образом
-
11
-
5
-
3
-
1
-
2
-
15
-
3
-
5
-
3
-
3
-
4
-
1
-
5
-
1
-
3
-
1
-
2
-
2
-
2
-
3
-
6
-
2
-
3
-
1
-
4
-
11
-
4
-
2
-
2
-
3
-
5
-
4
-
4
-
9
-
6
-
14
-
14
-
3
-
5
-
8
-
7
-
7
-
7
-
1
-
1
-
3
-
1
-
4
-
8
-
1