Цепить итерации в новый объект, но сохранить их класс? - PullRequest
0 голосов

Я работаю с объектом курсора в Python, который по сути является итератором. На самом деле у меня их два, и мне нужно соединить их в один. У этих объектов есть методы, которые мне нужно использовать в программе. Проблема в том, что itertools.chain (который в основном выполняет эту работу) возвращает объект цепочки, и у меня нет доступа к методам курсора.

Есть ли способ сохранить исходный класс, чтобы он был новый объект (связанный из двух), но имеющий все начальные методы?

1 Ответ

1 голос
/ 09 июля 2020

Вы можете создать цепочку логов c самостоятельно. Допустим, у вас есть два итератора разных классов, Foo и Bar:

class Foo:
    def __init__(self, n):
        self._iter = ((i * i for i in range(n)))
    def __next__(self):
        return next(self._iter)
    def foo_method(self):
        print("Yay, method in Foo was called")


class Bar:
    def __init__(self, n):
        self._iter = ((i / 2 for i in range(n)))
    def __next__(self):
        return next(self._iter)
    def bar_method(self):
        print("Yay, method in Bar was called")

Итераторы Foo имеют .foo_method(), а итераторы Bar имеют .bar_method().

Теперь давайте объединим их вместе:

class Chain:
    def __init__(self, *iters):
        self._cursor = 0
        self._iters = iters
    def __next__(self):
        """
        Chain iterators together.
        """
        if self._cursor == len(self._iters):
            raise StopIteration
        try:
            return next(self._iters[self._cursor])
        except StopIteration:
            self._cursor += 1
            return next(self)
    def __getattr__(self, name):
        """
        Pass everything unknown to the current iterator in chain.
        """
        if self._cursor == len(self._iters):
            raise ValueError("No current iterator")
        return getattr(self._iters[self._cursor], name)

Теперь, если вы сделаете что-то вроде

foo = Foo(3)
bar = Bar(3)

chain = Chain(foo, bar)

print(next(chain))
chain.foo_method()
print(next(chain))
print(next(chain))
print(next(chain))
print(next(chain))
chain.bar_method()

, на выходе будет

0
Yay, method in Foo was called
1
4
0.0
0.5
Yay, method in Bar was called

Это не сохраняет класс итераторов, но он позволяет вам получить доступ ко всем методам «текущего» итератора в цепочке.

...