Как мне изменить объект itertools.chain? - PullRequest
9 голосов
/ 15 февраля 2011

Моя функция создает цепочку генераторов:

def bar(num):
    import itertools
    some_sequence = (x*1.5 for x in range(num))
    some_other_sequence = (x*2.6 for x in range(num))
    chained = itertools.chain(some_sequence, some_other_sequence)
    return chained

Моя функция иногда должна возвращать chained в обратном порядке.Концептуально, вот что я хотел бы сделать:

if num < 0:
    return reversed(chained)
return chained

К сожалению:

>>> reversed(chained)
TypeError: argument to reversed() must be a sequence

Какие у меня варианты?

Это в некоторыхграфический рендеринг в реальном времени, поэтому я не хочу делать его слишком сложным / медленным.

EDIT : Когда я впервые задал этот вопрос, я не думал об обратимости генераторов.Как отмечали многие, генераторы не могут быть обращены вспять.

На самом деле я хочу обратить вспять уплощенное содержимое цепи;не только порядок генераторов.

Судя по ответам, нет единого вызова, который я могу использовать для обращения к itertools.chain, поэтому я думаю, что единственным решением здесь является использование списка, по крайней мере дляобратный случай, и, возможно, для обоих.

Ответы [ 7 ]

10 голосов
/ 15 февраля 2011
if num < 0:
    lst = list(chained)
    lst.reverse()
    return lst
else:
    return chained

reversed() нужна фактическая последовательность, потому что она повторяет ее в обратном порядке по индексу, и это не сработает для генератора (который имеет только понятие «следующий» элемент).

Так как вам все равно потребуется развернуть весь генератор для реверсирования, наиболее эффективный способ - это прочитать его в списке и развернуть список на месте с помощью метода .reverse().

9 голосов
/ 15 февраля 2011

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

Вместо этого используйте списки или создайте последовательности в обратном порядке с самого начала.

3 голосов
/ 16 февраля 2011

itertools.chain потребуется для реализации __reversed__() (это было бы лучше) или __len__() и __getitem__()

Поскольку это не так, и нет даже способа получить доступ к внутренним последовательностямвам нужно будет развернуть всю последовательность, чтобы иметь возможность ее перевернуть.

reversed(list(CHAIN_INSTANCE))

Было бы неплохо, если бы цепочка сделала доступной __reversed__(), когда все последовательности обратимы, но в настоящее время это не тактот.Возможно, вы можете написать свою собственную версию цепочки, которая делает

1 голос
/ 10 июня 2011
def reversed2(iter):
    return reversed(list(iter))
0 голосов
/ 15 февраля 2011

Теоретически вы не можете, потому что связанные объекты могут даже содержать бесконечные последовательности, такие как itertools.count(...).

Вы должны попытаться изменить свои генераторы / последовательности или использовать reversed(iterable) для каждой последовательности, если это применимо, а затем объединить их в цепочку в порядке очереди. Конечно, это сильно зависит от вашего варианта использования.

0 голосов
/ 15 февраля 2011

Работает ли это в вашем реальном приложении?

def bar(num):
    import itertools
    some_sequence = (x*1.5 for x in range(num))
    some_other_sequence = (x*2.6 for x in range(num))
    list_of_chains = [some_sequence, some_other_sequence]
    if num < 0:
        list_of_chains.reverse()
    chained = itertools.chain(*list_of_chains)
    return chained
0 голосов
/ 15 февраля 2011

reversed работает только с объектами, которые поддерживают len и индексацию. Вы должны сначала сгенерировать все результаты генератора, прежде чем обернуть reversed вокруг них.

Однако вы можете легко сделать это:

def bar(num):
    import itertools
    some_sequence = (x*1.5 for x in range(num, -1, -1))
    some_other_sequence = (x*2.6 for x in range(num, -1, -1))
    chained = itertools.chain(some_other_sequence, some_sequence)
    return chained
...