鄙人学习笔记
开发工具:Spyder
文章目录
- 迭代
- 举个例子1
- 举个例子2
- for循环原理
- 可迭代对象iterable
- 举个例子1
- 举个例子2
- 举个例子3
- 迭代器对象iterator
- yield关键字迭代原理
- 举个例子(我们将之前的MyRange类进行改写)
迭代
每一次对过程的重复为一次”迭代”,而每一次迭代得到的结果,会作为下一次迭代的初始值。例如:循环获取容器中的元素。
举个例子1
创建一个列表:
再输入以下代码:
结果:
可以看出,我们得到的结果和for循环遍历这个列表,得到的结果相同。
如果我们多写一个iterator.__next__(),会怎样呢?
结果:
会报错 python警告我们,要 Stop Iteration, 停止迭代!
举个例子2
还是创建原来的列表:
我们再利用以下方法迭代:
第39行代码这样写,其实相当于在except之后写了个异常基类:
结果:
我们发现,我们没有用for循环,也拿到了可迭代对象(列表)内元素。以上两个例子演示了for循环原理。
for循环原理
现在,我们对上面例子中的代码进行解释,进而阐述一下for循环原理
①获取迭代器对象
我们说,可迭代对象,是具有__iter__()方法,可以返回迭代器的对象。所以以后我们评判一个对象是不是可迭代对象时,就可以看一看,这个对象有没有__iter__()方法,如果有这个方法,则说明,这个对象是可以被迭代的。
②获取下一个元素(迭代)
有迭代器之后,我们就可以迭代了,__next__()的过程就是在迭代的过程,有__next__()我们就可以拿到下一个元素。
③停止迭代(StopIteration错误)
最后,我们总结一下for循环原理:
①获取迭代器对象
②循环迭代(调用迭代器的__next__()方法)
③捕获StopIteration异常
- 小问题
问:能够被for循环的条件是什么?
答:具有__iter__()方法的对象。
- 例子1
使用while + 迭代器,获取元祖(“小白”, “小黄”, “大白”)中所有元素。
代码:
t01 = ("小白", "小黄", "大白")iterator = t01.__iter__()
while True:
try:
item = iterator.__next__()
print(item)
except:
break
结果:
- 例子2
不使用for循环,获取字典{“小白”:0, “小黄”:6, “大白”:7}中的key和value.
代码:
d01 = {"小白":0, "小黄":6, "大白":7}iterator = d01.__iter__()
while True:
try:
key = iterator.__next__()
print(key, d01[key])
except:
break
结果:
备注:使用迭代器迭代字典,拿到的是字典的key
可迭代对象iterable
- 定义
具有__iter__()函数的对象,可以返回迭代器对象.
- 语法
创建可迭代对象:
class 可迭代对象名称:def __iter__(self):
return 迭代器
使用可迭代对象:
for 变量名 in 可迭代对象:语句
- 原理
while True:
try:
print(迭代器.__next__())
except StopIteration:
break
举个例子1
首先创建两个类:
再创建SkillManager对象,并试着迭代此对象的成员变量skills:
得到结果:
结果得到了列表内的各个Skill对象。
但是,如果我们只迭代SkillManager对象会怎样呢?我们看看下面这个例子。
举个例子2
利用例子1,创建的两个类:
再创建SkillManager对象,并试着迭代此对象:
运行:
报错!且python提示我们SkillManager对象是个不可迭代的对象。
接下来,我们就要让SkillManager可迭代!
我们先要在SkillManager类里增加一个__iter__()方法,使他变为可迭代对象。 这个__iter__()被调用后,应该返回一个迭代器类对象SkillIterator。这个迭代器类对象里应该有一个__next__()方法,用于返回下一个元素。在__next__()方法里应该抛出一个索引越界异常,当被迭代对象全部迭代完后,再获取下一个元素,则会抛出异常。具体情况,我们看看下面的代码。
现在我们看一下SkillManager类:
再看一下SkillIterator类:
创建对象,并开始利用for循环原理,进行迭代:
我们再运行一下,看一下运行结果:
不错!可迭代对象内元素全部拿到了。
备注1:由上面的过程我们也可以看出,可迭代对象不会直接return它的元素,而是由迭代器return了可迭代对象内的元素。
备注2:若我们用for循环,则它也会先获取迭代器对象,获取完迭代器对象后,再用迭代器对象不断的调用__next__()方法,直到迭代器对象抛出异常,for再进行异常处理。
举个例子3
参照下例代码,定义MyRange类,实现相同效果:
代码:
def __init__(self, stop):
self.stop = stop
self.start = 0
def __next__(self):
if self.start + 1 > self.stop:
raise StopIteration()
temp = self.start
self.start += 1
return temp
class MyRange:
def __init__(self, stop):
self.stop = stop
def __iter__(self):
# 创建迭代器对象
return MyRangeIterator(self.stop)
iterator = MyRange(5)
for item in iterator:
print(item)
结果:
备注:谁要被for,谁要就有__iter__()方法,这个方法可以获取迭代器,迭代器内部具体怎么写?看需求!迭代器中有__next__(),可以返回下一个元素。
迭代器对象iterator
- 定义
可以调用__next__()函数,并返回下一个值得对象。
- 语法
def __init__(self, 聚合对象):
self.聚合对象 = 聚合对象
def __next__(self):
if 没有元素:
raise StopIteration
return 聚合对象内元素
- 说明
聚合对象通常是容器对象。
- 作用
使用者只通过一种方式(for循环),便可以简洁明了获取聚合对象中的各个元素,而又无需了解可迭代对象的内部存储结构。
==备注!==若我们在__iter__()方法内不返回自己创建的迭代器对象,而用yield关键字自动生成迭代器对象,会怎样呢?
请看以下案例
代码:
结果:
执行过程:
①客户端调用__iter__()方法,__iter__()方法不执行, 进入while循环.
②客户端调用__next__()方法,__iter__()方法执行,先执行print("准备返回第一个元素"), 执行到yield语句, 将yield后的数据作为__next__()方法的返回值return给item, 并且暂时离开__iter__()方法, 继续执行while循环中的print(item).
③当再次调用__next__()方法时,从上次离开的代码开始执行,再运行到下一个yield语句,return数据之后,并再次暂时离开.
④待执行完__iter__()方法体,若再次调用__next__()方法,会自动抛出StopIteration异常.
yield关键字迭代原理
- 原理
如果方法体中包含yield关键字,那么会自动生成迭代器对象.
生成迭代器代码的大致规则:
①将yield关键字前的代码,放到__next__()方法中.
②将yield关键字后的数据,作为__next__()方法的返回值.
举个例子(我们将之前的MyRange类进行改写)
代码:
结果:
若我们不定义类,而只定义包含yield的方法,来满足我们迭代的需求,该怎么做呢?
代码:
结果:
我们说这项技术,就叫做生成器generator函数.
【文章原创作者:高防ip http://www.558idc.com/gfip.html欢迎留下您的宝贵建议】