У меня есть несколько генераторов Python, которые я хочу объединить в новый генератор.Я легко могу сделать это с помощью написанного от руки генератора, используя кучу операторов yield
.
С другой стороны, модуль itertools
создан для таких вещей, и мне кажется, чтоПитонный способ создания генератора, который мне нужен, - это объединить различные итераторы этого itertools
модуля.
Однако в рассматриваемой задаче это вскоре становится довольно сложным (генератор должен поддерживать своего рода состояние--- например, обрабатываются ли первый или более поздние элементы ---, i-тый вывод дополнительно зависит от условий на i-тых элементах ввода, и различные списки ввода должны обрабатываться по-разному, прежде чем они будут присоединены ксгенерированный список.
Поскольку состав стандартных итераторов, которые могли бы решить мою проблему, - из-за одномерной природы записи исходного кода - почти непостижим, интересно, есть ли какие-либо преимуществаиспользование стандартных генераторов itertools
по сравнению с функциями, написанными от руки (в основном и более продвинутомSES).На самом деле, я думаю, что в 90% случаев рукописные версии намного легче читать - вероятно, из-за их более императивного стиля по сравнению с функциональным стилем цепочки итераторов.
РЕДАКТИРОВАТЬ
Чтобы проиллюстрировать мою проблему, вот (игрушечный) пример: пусть a
и b
будут двумя итерациями одинаковой длины (входные данные).Элементы a
состоят из целых чисел, элементы b
сами являются итерируемыми, отдельные элементы которых являются строками.Вывод должен соответствовать выводу следующей функции генератора:
from itertools import *
def generator(a, b):
first = True
for i, s in izip(a, b):
if first:
yield "First line"
first = False
else:
yield "Some later line"
if i == 0:
yield "The parameter vanishes."
else:
yield "The parameter is:"
yield i
yield "The strings are:"
comma = False
for t in s:
if comma:
yield ','
else:
comma = True
yield t
Если я записываю ту же программу в функциональном стиле, используя выражения генератора и модуль itertools
, я получаю что-то вроде:
from itertools import *
def generator2(a, b):
return (z for i, s, c in izip(a, b, count())
for y in (("First line" if c == 0 else "Some later line",),
("The parameter vanishes.",) if i == 0
else ("The parameter is:", i),
("The strings are:",),
islice((x for t in s for x in (',', t)), 1, None))
for z in y)
ПРИМЕР
>>> a = (1, 0, 2), ("ab", "cd", "ef")
>>> print([x for x in generator(a, b)])
['First line', 'The parameter is:', 1, 'The strings are:', 'a', ',', 'b', 'Some later line', 'The parameter vanishes.', 'The strings are:', 'c', ',', 'd', 'Some later line', 'The parameter is:', 2, 'The strings are:', 'e', ',', 'f']
>>> print([x for x in generator2(a, b)])
['First line', 'The parameter is:', 1, 'The strings are:', 'a', ',', 'b', 'Some later line', 'The parameter vanishes.', 'The strings are:', 'c', ',', 'd', 'Some later line', 'The parameter is:', 2, 'The strings are:', 'e', ',', 'f']
Это, возможно, более элегантно, чем мое первое решение, но выглядит как произведение "один раз не пойми позже"кода.Мне интересно, имеет ли этот способ написания моего генератора достаточно преимуществ, чтобы его можно было сделать.
PS: Я полагаю, что часть моей проблемы с функциональным решением заключается в том, чтобы минимизировать количество ключевых слов в Python,некоторые ключевые слова, такие как «for», «if» и «else», были переработаны для использования в выражениях, так что их размещение в выражении требует привыкания (упорядоченность в выражении генератора z for x in a for y in x for z in y
выглядит, по крайней мере для меня, менееестественно, чем порядок в классической for
петле: for x in a: for y in x: for z in y: yield z
).