【问题标题】:Python: creating a class that could be iterated circularlyPython:创建一个可以循环迭代的类
【发布时间】:2019-04-07 16:31:23
【问题描述】:

我想在 Python 中创建一个行为类似于列表但可以循环迭代的类 用例示例:

myc = SimpleCircle()
print(len(myc))
j = iter(myc)
for i in range (0, 5):
    print(next(j))

它将打印 一种 b C d 一个

到目前为止我尝试的代码是下面的代码 我知道问题出在我的__next__

方法 顺便说一句,这似乎被忽略了,即使我没有实现它,我也可以使用下一个

class SimpleCircle:
    def __init__(self):
        self._circle = ['a', 'b', 'c', 'd']
        self._l = iter(self._circle)


    def __len__(self):
        return len(self._circle)

    def __iter__(self):
        return (elem for elem in self._circle)

    def __next__(self):
        try:
            elem = next(self._l)
            idx = self._circle.index(elem)
            if idx < len(self._circle):
                return elem
            else:
                return self._circle[0]
        except StopIteration:
            pass

【问题讨论】:

标签: python iterator next circular-list


【解决方案1】:

这是一个基本的非 itertools 实现:

class CyclicIterable:
    def __init__(self, data):
        self._data = list(data)

    def __iter__(self):
        while True:
            yield from self._data

cycle = CyclicIterable(['a', 'b', 'c', 'd'])
for i, x in zip(range(5), cycle):
    print(x)

请注意,没有必要实现 __next__,因为 Cycle 类本身,就像 list不是迭代器。要显式地从中取出迭代器,您编写:

it = cycle.__iter__()
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))

当然,您可以实例化任意数量的迭代器。

【讨论】:

  • yield from 行中不需要生成器表达式。 yield from (x for x in self._data)yield from self._data 相同(但更慢且更难理解)。
  • @Blckknght 哎呀我忘了从 OP 复制时删除它:P
  • 非常聪明的实现。我花了一段时间才明白发生了什么。请您考虑写一个简短的说明为什么/如何循环?
  • 相当于while True: for x in self._data: yield x
【解决方案2】:

这实际上已经存在于itertools.cycle,例如:

from itertools import cycle

for x in cycle(['a', 'b', 'c', 'd']):
    print(x)

将继续重复该元素。

接下来,您在这里将可迭代对象和迭代器混为一谈,它们通常是不同的东西。

作为一个可迭代对象,我们可以从 self._circle 继续迭代:

class SimpleCircle:
    def __init__(self):
        self._circle = ['a', 'b', 'c', 'd']

    def __len__(self):
        return len(self._circle)

    def __iter__(self):
        if not self._circle:
            raise StopIteration
        while True:
            yield from self._circle

或者对于一个迭代器

class CycleIterator:

    def __init__(self, iterable):
        self.iterator = iter(iterable)
        self.__next__ = self._iternext
        self.idx = 0
        self.list = []

    def _iternext(self):
        try:
            x = next(self.iterator)
            self.list.append(x)
            return x
        except StopIteration:
            self.__next__ = self._iterlist
            return self._iterlist()

    def _iterlist(self):
        try:
            return self.list[self.index]
        except IndexError:
            raise StopIteration
        finally:
            self.index = (self.index + 1) % len(self.list)

【讨论】:

  • 很清楚,谢谢。关于迭代器和迭代器的混合,如果我理解得很好,如果我想要一个可迭代的类,我只需实现 iter ,而不是如果我想实现一个迭代器类,我必须实现 _next
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-15
  • 1970-01-01
  • 2021-04-29
  • 2019-07-15
  • 2021-01-23
  • 2015-07-09
  • 1970-01-01
相关资源
最近更新 更多