迭代对象就是可以使用for in 来遍历的对象,常见的list dict string 等都是可迭代的对象,除此之外我们可以定义自己的对象为可迭代对象,这样就可以直接在对象上使用for 循环遍历了
只要类里面含有__iter()__ 和__next()__ 类方法,就可以实现可迭代对象
其中:
__iter()__ 方法来返回一个可迭代对象,一般就是返回self 本身就可以了
__next()__方法用来返回每次迭代的值,一般在可迭代类里需要维护一个控制迭代次数的变量,这个变量在每次调用__next()__方法时都要更新,表示迭代到的位置
class users:
def __init__(self,user_list):
self.users=user_list
self.count=len(user_list)
def __iter__(self): # 必须要有这个函数,虽然只是返回自己,不然在for语句不认为当前对象可以使用for循环
return self # 没有这个函数的话,会报错 TypeError: 'users' object is not iterable
def __next__(self):
if self.count>0:
self.count-=1
return self.users[self.count]
else:
raise StopIteration
u1=users(['jack','mike','tom'])
for x in u1:
print(x)
#输出:
tom
mike
jack
分析一下迭代对象在for 语句里面的执行过程:
语句for x in u1 在开始执行前会获取u1对象的__iter()__方法来获取可迭代对象,这里获得的就是u1本身,然后for 循环内部会不停的调用u1.__next()__来获取值,直到遇到StopIteration异常,其实python内置的函数next也能实现相同的功能,通过多次调用next(u1)每次都会获取不同的返回,
u1=users(['jack','mike','tom'])
print(next(u1))
print(next(u1))
print(next(u1))
print(next(u1))
#输出:
tom
mike
jack
Traceback (most recent call last):
File "C:/Users/young.yu/Desktop/test.py", line 23, in <module>
print(next(u1))
File "C:/Users/young.yu/Desktop/test.py", line 14, in __next__
raise StopIteration
StopIteration
可以看到第四次调用的时候触发了StopIteration后退出。
为什么这里print(next(u1))每次使用相同的函数,相同的对象,但返回的却不同?因为每次调用next(u1)其实在u1对象内部都会更新属性self.count的值,而迭代对象就是通过这个属性来控制返回的值和迭代次数的。
如果没有维护这么一个属性的话,for 循环会怎么样?
class users:
def __init__(self,user_list):
self.users=user_list
def __iter__(self):
return self
def __next__(self):
for i in self.users:
return i
u1=users(['jack','mike','tom'])
for x in u1: # 这里会无限循环输出jack
print(x)
print(next(u1)) # 下面这些调用都会输出一样的jack
print(next(u1))
print(next(u1))
print(next(u1))
上面的代码因为没有在迭代对象里维护一个控制迭代次数的对象,所以每次next(u1)都是完全一样的环境,都输出一样的值