什么是可迭代对象?
答,有_iter_()函数的对象就成为可迭代对象。如果你再追问:iter()函数有什么用?那告诉你,像for循环就是一个框架协议,就是靠着使用_iter_()来实现的。所以弄懂_iter_()有什么用,就是弄懂for循环在底层干什么事情弄懂for循环原理的过程。
下面举例说明,如果我们有一个自定义的类想使用for遍历它,代码中所示:
"""
类:技能类,作用暂时不写
"""
class Skill:
def __init__(self):
pass
"""
类:技能管理类
作用:管理技能,包括对类的增加、访问
"""
class SkillManage:
def __init__(self):
self._skills = []
def add_skill(self,skill):
self._skills.append(skill)
m01 = SkillManage()
m01.add_skill(Skill())
m01.add_skill(Skill())
m01.add_skill(Skill())
for m001 in m01:
print(m01)
输出:
File "C:/Users/ZBZ/PycharmProjects/untitled/iter_analyse.py", line 23, in <module>
for m001 in m01:
TypeError: 'SkillManage' object is not iterable
如图错误提示,错误类型为类型不是可迭代的。那么我们就按照可迭代对象的定义给我们的自定义类添加_iter_()方法。
"""
类:技能类,作用暂时不写
"""
class Skill:
def __init__(self,name):
self.name = name
"""
类:技能管理类
作用:管理技能,包括对类的增加、访问
"""
class SkillManage:
def __init__(self):
self._skills = []
def add_skill(self,skill):
self._skills.append(skill)
def __iter__(self):
return SKillIterator(self._skills)
"""
类:迭代器
"""
class SKillIterator:
def __init__(self,target):
self.__skills = target
self.__index = 0
def __next__(self):
if(self.__index == len(self.__skills)):
raise StopIteration
temp = self.__skills[self.__index]
self.__index += 1
return temp
m01 = SkillManage()
m01.add_skill(Skill("打狗棒法"))
m01.add_skill(Skill("御女心经"))
m01.add_skill(Skill("降龙十巴掌"))
for m0 in m01:
print(m0.name)
改成这样就可以使用for,表示可迭代了。其中主要的改动就是在SKillManage中添加_iter_()函数,在其中返回迭代器。那么又添加了一个迭代器类,迭代器中要有_next_()方法,返回一个对象,并且记录返回的索引,当集合中所有的对象都已经返回一遍后要记得停止。
这个就是迭代器思想,next()方法执行一次,返回下一个对象。然后迭代器的实现原理或者说本质就是上面的做法,我们可以借助yield来自动生成迭代器的类,代码改为如下:
"""
类:技能类,作用暂时不写
"""
class Skill:
def __init__(self,name):
self.name = name
"""
类:技能管理类
作用:管理技能,包括对类的增加、访问
"""
class SkillManage:
def __init__(self):
self._skills = []
self._index =0
def add_skill(self,skill):
self._skills.append(skill)
def __iter__(self):
while self._index < len(self._skills):
# yield 作用: 将下列代码改为迭代器模式的代码.
# 生成迭代器代码的大致规则:
# 1. 将yield以前的语句定义在next方法中
# 2. 将yield后面的数据作为next方法返回值
yield self._skills[self._index]
self._index += 1
m01 = SkillManage()
m01.add_skill(Skill("打狗棒法"))
m01.add_skill(Skill("御女心经"))
m01.add_skill(Skill("降龙十巴掌"))
m01.add_skill(Skill("九阴白骨爪"))
for m0 in m01:
print(m0.name)
把上面的继续优化,深入之后开始浅出:
"""
类:技能类,作用暂时不写
"""
class Skill:
def __init__(self,name):
self.name = name
"""
类:技能管理类
作用:管理技能,包括对类的增加、访问
"""
class SkillManage:
def __init__(self):
self._skills = []
self._index =0
def add_skill(self,skill):
self._skills.append(skill)
def __iter__(self):
# while self._index < len(self._skills):
# # yield 作用: 将下列代码改为迭代器模式的代码.
# # 生成迭代器代码的大致规则:
# # 1. 将yield以前的语句定义在next方法中
# # 2. 将yield后面的数据作为next方法返回值
# yield self._skills[self._index]
# self._index += 1
for skill in self._skills:
yield skill
m01 = SkillManage()
m01.add_skill(Skill("打狗棒法"))
m01.add_skill(Skill("御女心经"))
m01.add_skill(Skill("降龙十巴掌"))
m01.add_skill(Skill("九阴白骨爪"))
for m0 in m01:
print(m0.name)
借助yield,iter()方法仅仅两句达成我们的目标,可以被for。这就变成了生成器,每次返回一个集合中的值,但是占用的内存只有一个对象的大小。
另外可以自己写一个自己的Rang()方法,代替Rang,体会生成器的作用:
def MyRang(stopvalue):
num = 0
while num < stopvalue:
yield num
num += 1
for i in MyRang(10):
print(i)
那么就可以自定义自己的Myrang方法,做成奇数生成器、偶数生成器等等。如下:
"""
奇数生成器
"""
def MyOddtermRang(stopvalue):
num = 1
while num < stopvalue:
yield num
num += 2
"""
偶数生成器
"""
def MyEventermmRang(stopvalue):
num = 2
while num < stopvalue:
yield num
num += 2
for i in MyOddtermRang(10):
print(i)
for i in MyEventermmRang(10):
print(i)
从迭代对象、到迭代器,再到生成器,原理一定要理解清晰。
三者关系,其实就是生成器 = 迭代对象 + 迭代器
比较详细的一些Python自带类型的关于迭代的举例,可参阅:https://www.cnblogs.com/notfind/p/11520124.html