Я знаю, как работает yield
. Я знаю перестановку, думаю, это просто математическая простота.
Но какая yield
истинная сила? Когда я должен его использовать? Простой и хороший пример лучше.
Я знаю, как работает yield
. Я знаю перестановку, думаю, это просто математическая простота.
Но какая yield
истинная сила? Когда я должен его использовать? Простой и хороший пример лучше.
yield
лучше всего использовать, когда у вас есть функция, которая возвращает последовательность, и вы хотите перебирать эту последовательность, но вам не нужно иметь каждое значение в памяти сразу.
Например, у меня есть python script, который анализирует большой список файлов CSV, и я хочу вернуть каждую строку, которая будет обрабатываться в другой функции. Я не хочу хранить мегабайты данных в памяти все сразу, поэтому я yield
каждую строку в структуре данных python. Таким образом, функция для получения строк из файла может выглядеть примерно так:
def get_lines(files):
for f in files:
for line in f:
#preprocess line
yield line
Затем я могу использовать тот же синтаксис, что и со списками, для доступа к выходному сигналу этой функции:
for line in get_lines(files):
#process line
но я сохраняю много использования памяти.
Проще говоря, yield
дает вам генератор. Вы использовали бы это, где обычно использовали бы функцию return
в функции. Как действительно надуманный пример, вырезанный и вставленный из подсказки...
>>> 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
<generator object yield_odd_numbers at 0x1029c6f50>
>>> bar.next()
1
>>> bar.next()
3
>>> bar.next()
5
Как вы можете видеть, в первом случае foo
хранит сразу весь список в памяти. Это не большое дело для списка с 5 элементами, но что, если вы хотите список из 5 миллионов? Мало того, что это огромный eater памяти, он также требует много времени, чтобы построить в то время, когда функция вызывается. Во втором случае bar
просто дает вам генератор. Генератор является итерируемым, что означает, что вы можете использовать его в цикле for и т.д., Но каждое значение может быть доступно только один раз. Все значения также не сохраняются в памяти одновременно; объект-генератор "запоминает", где он был в цикле в последний раз, когда вы его назвали, - таким образом, если вы используете итерируемый (скажем) счет до 50 миллиардов, вам не нужно считать до 50 миллиардов всех сразу и хранить 50 миллиардов номеров для подсчета. Опять же, это довольно надуманный пример, вы, вероятно, использовали бы itertools
, если бы вы действительно хотели сосчитать до 50 миллиардов.:)
Это самый простой вариант использования генераторов. Как вы сказали, его можно использовать для написания эффективных перестановок, используя yield
, чтобы проталкивать вещи через стек вызовов вместо использования какой-то переменной стека. Генераторы также могут использоваться для специализированного обхода дерева и всех других вещей.
Дальнейшее чтение:
Другое использование - в сетевом клиенте. Используйте "yield" в функции генератора для циклического развертывания через несколько сокетов без сложности потоков.
Например, у меня был аппаратный тестовый клиент, которому необходимо было отправить R, G, B плоскости изображения в прошивку. Данные необходимо отправить в замок: красный, зеленый, синий, красный, зеленый, синий. Вместо того, чтобы порождать три потока, у меня был генератор, который читал из файла, закодировал буфер. Каждый буфер был "доходным buf". Конец файла, возвращаемая функция и у меня был конец итерации.
Мой клиентский код зациклился на трех функциях генератора, получив буферы до конца итерации.
Я читаю структуры данных и алгоритмы в Python
Существует функция Фибоначчи, использующая выход. Я думаю, что это лучший момент для использования доходности.
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a+b
вы можете использовать это как:
gen = fibonacci()
for i, f in enumerate(gen):
print(i, f)
if i >= 100: break
Итак, я думаю, может быть, когда следующий элемент зависит от предыдущих элементов, например, цифровых фильтров, пора использовать yield.