迭代器、可迭代对象、for循环range本质
迭代器
迭代器的定义
1/ 当一个类中 定义了 __iter__ 和 __next__ 两个方法,就是一个迭代器
2/ __iter__ 方法需要返回对象本身,也就是 self
3/ __next__ 方法,返回下一个数据,如果没有数据了,需要抛出一个 StopIteration 的异常
定义一个迭代器
class It():
def __init__(self) -> None:
self.count = 0
def __iter__(self):
return self
def __next__(self):
self.count +=1
if self.count == 5:
raise StopIteration()
return self.count
这个类It 就是一个迭代器,而这个类的实例就是一个迭代器对象
obj = It() # obj就是一个迭代器对象
print(obj.__next__())
print(obj.__next__())
print(obj.__next__())
print(obj.__next__())
print(obj.__next__())
输出:
1
2
3
4
第五个print 报错 StopIteration()
obj = It()
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj))
同上
for 循环本质
obj = It()
for item in obj:
print(item)
输出:
1 2 3 4
# 1/ for循环会去 执行迭代器对象obj的__iter__方法 并获取返回值【迭代器对象】
# 2/ 一直不停的调用 next(对象) 并赋值给 item
思考一个问题
#修改代码为:
for item in obj:
print(next(obj))
print(item)
#输出 什么?
分析:
输出的结果为:
2 1 4 3
1/ for循环先执行obj的__iter__方法 返回的是obj 的self本身
2/ 然后调用next(obj) 获取返回值 1 赋值给item
3/ print(next(obj)) 这里再执行了一次 next(obj) 所以输出 2
4/ 再来输出item 所以输出刚赋值的 1
5/ 再调用next(obj) 获取返回值 3 赋值给item
6/ print(next(obj)) 这里再执行了一次 next(obj) 所以输出 4
7/ 输出刚赋值的item 所以输出 3
8/ 再次尝试调用next(obj)赋值给 item 这时候5 已经触发了StopIteration终止循环
所以输出的是 2 1 4 3
生成器
生成器本质上是一种特殊的迭代器
def func():
yeild 'aa'
yeild 'bb'
# 这里底层是用 generator 生成器类创建的一个对象,生成器内部也声明了 __iter__ __next__
obj = func()
print(type(obj)) # <class 'generator'>
print(obj.__next__()) #aa
print(next(obj)) #bb
print(next(obj)) # 抛出StopIteration异常
可迭代对象
注意区分概念:
1/ 迭代器对象: 由迭代器 实例化出来的对象 为迭代器对象
2/ 可迭代对象: 如果一个类 有__iter__方法,且返回了一个 迭代器对象,那么这个类实例化出来的对象就为 可迭代对象
举例:
# 这是一个迭代器,实现了 __iter__ 和 __next__ 两个方法,并且iter返回本身
class It():
def __init__(self) -> None:
self.count = 0
def __iter__(self):
return self
def __next__(self):
self.count +=1
if self.count == 5:
raise StopIteration()
return self.count
obj1 = It() ## 这个obj就是一个 迭代器对象
#这个类 并不是迭代器,因为都没有__next__方法,但是这个类有__iter__方法,并且返回的是一个 迭代器对象【It 为迭代器,实例化是迭代器对象】
class Demo:
def __iter__(self):
return It()
demo = Demo() ## 这个demo就是一个 可迭代对象
for i in demo:
print(i)
# 同理,生成器是一个特殊的迭代器,所以生成器对象也是一个迭代器对象
def func():
yeild 1
yeild 2
class Demo2:
def __iter__(self):
return func()
for i in demo2:
print(i)
class T:
def __iter__(self):
yield 1
yield 'xx'
yield 'haha'
for i in T():
print(i)
理解练习
for i in range(10):
print(i)
#这个 range(10)返回的一定是一个 可迭代对象
v1 = range(10)
print(dir(v1))
# 返回的dir 发现只有__iter__, 并没有__next__,所以range()返回的只是一个可迭代对象,并不是迭代器对象
#测试一下
next(v1) # 会报错 'range' object is not an iterator 说明不是一个迭代器对象
v2 = v1.__iter__() # 可迭代对象的iter方法返回的是一个迭代器对象
print(dir(v2)) #这里就可以看到有__iter__ 有 __next__ 方法了
print(v2,type(v2))# <range_iterator object at 0x7f5eac2ae960> <class 'range_iterator'>
v2.__next__()
next(v2) 执行就成功了
需求:
自定义一个range,要求是一个闭区间,比如原来的range(5) 只有 0 1 2 3 4,这里需要输出 0 1 2 3 4 5
class MyIterRange():
def __init__(self,min,max):
self.min = min
self.max = max
self.strat = 0
def __iter__(self):
return self
def __next__(self):
self.min = self.min+self.strat
self.strat = 1
if self.min > self.max:
raise StopIteration()
return self.min
class MyRange():
def __init__(self,min,max):
self.min = min
self.max = max
def __iter__(self):
return MyIterRange(self.min,self.max)
# 用可迭代对象
for i in MyRange(1,9):
print(i)
# 直接用迭代器对象,迭代器对象一定是个可迭代对象
for i in MyIterRange(-4,1):
print(i)
或者用更简单的方法:
class MyYieldRange():
def __init__(self,min,max):
self.min = min
self.max = max
def __iter__(self):
while self.min <= self.max:
yield self.min
self.min+=1
for i in MyYieldRange(-1,8):
print(i)
结论
-
迭代器 实例化 生成 迭代器对象
-
生成器是一个特殊的迭代器,实例化出来的也是一个迭代器对象
-
可迭代对象 不一定是 迭代器对象 ,但是迭代器对象一定是可迭代对象
-
for 循环本质是先去调用可迭代对象的__iter__方法,获取返回的迭代器对象,然后不停的调用迭代器对象的__next__方法 直到StopIteration()