У меня есть несколько генераторов Python, которые я хочу объединить в новый генератор. Я могу легко сделать это с помощью написанного от руки генератора, используя связку операторов yield
.
С другой стороны, модуль itertools
создан для таких вещей и для меня похоже, что питонический способ создания генератора, который мне нужен, состоит в том, чтобы соединить вместе различные итераторы этого модуля itertools
.
Однако в рассматриваемой проблеме рукописные версии намного легче читать - вероятно, из-за их более императивного стиля по сравнению с функциональным стилем объединения итераторов.
EDIT
Чтобы проиллюстрировать мою проблему, вот (игрушечный) пример : Пусть 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
Если я запишу ту же программу в функциональном стиле, используя выражения генератора и Пусть 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
Если я запишу ту же программу в функциональном стиле, используя выражения генератора и Пусть 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
выглядит, по крайней мере, для меня, менее естественным, чем порядок в классическом для
цикла: для x в a: для y в x: для z в y: вывести z
).