Python可迭代类
__iter__()
和__next__()
python中我们常常会用到for循环结构(for 元素 in 元素来源: …)for循环后面的元素来源实际上就是一个可以迭代的对象。for … in …语句其实做了两件事,第一件事是获取一个可迭代对象,即调用了__iter__()
函数;第二件事就是循环过程,也就是在循环地调用__next__()
函数。
也就是说,我们可以通过__iter__()
和__next__()
来自定义一个可以迭代的类:
# 定义一个斐波那契类
Class Fib:
def __init__(self,num):
self.num = num # 最大迭代次数
self.recorder = 0
self.a,self.b = 0,1
# 实例本身就是迭代对象,故返回自己
def __iter__(self):
return self
def __next__(self):
self.a,self.b = self.b,self.a + self.b
self.recorder += 1
# 当超过最大迭代次数时抛出异常
if self.recorder >= self.num:
raise StopIteration()
else:
return self.a
# 直接迭代Fib()的实例对象
it = Fib(10)
for n in it:
print(n)
# 第一个for循环结束的时候,next()已经走到迭代对象的末尾
# 再次for循环是从末尾继续往后遍历,不会遍历到任何元素
for m in it:
print(m) # 无输出
__iter__()
的作用是将迭代对象本身返回出去,而__next__()
的作用是为了获取迭代对象中的元素。所以上面的类中也可以不写__iter__()
函数,同样也能实现迭代。
class Fib:
def __init__(self,num):
self.num = num
self.recorder = 0
self.a,self.b = 0,1
def __next__(self):
self.a,self.b = self.b,self.a + self.b
self.recorder += 1
if self.recorder >= self.num:
raise StopIteration()
else:
return self.a
# 示例一个Fib对象
itr = Fib(10)
# 利用next()手动获取itr中的元素
for i in range(10):
print(next(itr))
# 注意:next()获取只能一直向后取
for j in range(10):
print(next(itr)) # 报错,上一个for循环已经让next()指向了itr的末尾,此处的for循环还是从末尾的位置继续向后获取元素
__getitem__()
如果说上述的__next__()
是让外部可以使用next()函数依次获取下一个元素的话,__getitem__()
的作用就是可以让外部使用索引的方式获取制定位置的元素
class DataTest:
def __init__(self,num):
self.num = num
def __getitem__(self,index):
if index < self.num:
return f"这是索引{index}指向的元素"
else:
raise StopIteration
# 可直接从头开始遍历
data = DataTest(20)
for i in data:
print(i)
print("遍历结束")
print("----------------")
# 也可以通过索引获取制定位置的元素
print(data[0])
print(data[14])
print(data[19])
# 再次for循环也是从头重新开始遍历
for j in data:
print(j)