Python:创建一个可以循环迭代的class
Python: creating a class that could be iterated circularly
我想在 Python 中创建一个行为类似于列表但可以循环迭代的 class
用例示例:
myc = SimpleCircle()
print(len(myc))
j = iter(myc)
for i in range (0, 5):
print(next(j))
它将打印
一种
b
C
d
一个
到目前为止我试过的代码是下面的
我知道问题出在我的 __next__
方法
顺便说一下,这似乎被忽略了,即使我不实现它,我也可以使用 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
这实际上已经存在 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)
这是一个基本的非 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
class 本身就像 list
一样, 不是迭代器。 要明确地从中得到一个迭代器,你写:
it = cycle.__iter__()
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
当然,您可以实例化任意数量的迭代器。
我想在 Python 中创建一个行为类似于列表但可以循环迭代的 class 用例示例:
myc = SimpleCircle()
print(len(myc))
j = iter(myc)
for i in range (0, 5):
print(next(j))
它将打印 一种 b C d 一个
到目前为止我试过的代码是下面的
我知道问题出在我的 __next__
方法 顺便说一下,这似乎被忽略了,即使我不实现它,我也可以使用 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
这实际上已经存在 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)
这是一个基本的非 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
class 本身就像 list
一样, 不是迭代器。 要明确地从中得到一个迭代器,你写:
it = cycle.__iter__()
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
当然,您可以实例化任意数量的迭代器。