迭代就是快速地在原来的版本上添加新功能。 迭代器是Python中一种特殊的对象。 迭代就是在原来的基础上,得到一个新的东西。
一个对象是可迭代的 <==> 能放到 for x in 后面 <==> instance(对象, Iterable)为True <==> 有__iter__()方法 迭代器对象 <==> isinstance(xxx, Iterator) <==> 实现了__iter__() 和__next__()方法
一、可迭代对象1. 什么是可迭代的对象?一个对象是可迭代的 <==> 能放到 for x in 后面 <==> instance(对象, Iterable)为True <==> 有__iter__()方法
能够放在for x in 后面的,就是可迭代的(iterable),比如字符串、列表、元组、字典、集合。但是数字类型就不行,比如:
例1: 结果:
2. 怎么判断一个对象是可迭代的?我怎么知道一个对象是否可以迭代呢? 只要判断是Iterable的实例对象就可以了。【例2】
例2:
结果:
前两个可以迭代。12不能迭代。
3. 如果我创建了一个类,怎么让这个类是可迭代的呢?如果想要一个对象称为一个可迭代的对象(即可以使用for循环),那么必须实现__iter__()方法。【例3】【例4】
例4:
实现了__iter__方法,就是可迭代对象了,就能够放到for后面了。 但是还是报错了,说iter()方法返回的不是一个迭代器对象。
那什么是迭代器对象呢?为什么iter()方法返回呢? 我们需要知道什么是迭代器,以及for循环的原理。
二、迭代器迭代器对象 <==> 实现了__iter__() 和__next__()方法 <==> isinstance(xxx, Iterator)
结果:
三、for循环执行原理for temp in xxx_obj: pass
步骤1. 判断xxx_obj是否是可迭代。如果不可迭代会报错。【例1】 步骤2. 如果是可迭代的,for循环会自动调用iter()函数,并传入xxx_obj对象。iter()函数,会自动xxx_obj对象的__iter__()方法,得到返回值。【例2】【例3】【例4】 步骤3. iter()函数的返回值要求是一 报错。【例2】【例3】 步骤4. 返回了迭代器iterator之后,for每次循环就调用一次next(iterator)函数。next(iterator)函数会自动调用迭代器iterator的__next__()方法,得到一个结果。【例5】 迭代器中的__next__返回的是什么,temp就是什么。。每for一次,就会调用一次next,next返回什么就用什么。。【例6】
for循环传入的参数是xxx_obj,xxx_obj返回的是一个迭代器。迭代器的__next__()方法给for循环什么,for循环就用什么。
例1:如果不是可迭代对象,则会报错。
结果:
例2:验证:iter()函数会自动调用对象的__iter__()方法。并且如果返回值不是迭代器会报错。
结果:
例3:iter()返回的是一个迭代器对象,就不报错了。
结果:
例4:验证for循环会自动调用__iter__()方法。
结果:
说明了,for循环会调用iter()方法。
例5:next(迭代器)方法会自动调用迭代器的__next__方法。
结果:
例6:每for一次就是返回一次迭代器的结果。
结果:
共执行了5次for循环。迭代器返回了五次"aaa"。
四、自己实现一个类,能够使用for循环遍历其中的值现在我们已经知道了for循环的原理。我们接着上面的例6完成后面的部分,完成for循环能够遍历到Classmate类的列表的内容。
现在迭代器中的__next__方法能够返回"aaa"了。但是我们想返回的是classmate对象的列表。所以只要把classmate传给__next__方法。就行了。
【改进一】
结果: 可以输出小王了。
【改进二】增加遍历的代码
结果:
【改进三】怎么结束遍历呢? for循环并不知道一共有几个,当遍历完了,取到的是None。
结果:
当取完之后,抛出一个异常。当for循环得到异常之后,就停了。
到此为止,for循环就实现了~~~~~~~~~~~~~~~~~~~~~~~~~~~
【继续改进:终版】 我们看到,是实现了__iter__()方法就是可迭代对象,可迭代对象返回 了迭代器对象。而迭代器对象实现了__iter__() 和__next__()方法,__next__方法又返回了可迭代对象的内容。 那我直接在可迭代对象中,加上__next__方法,就可以即是可迭代对象,又是迭代器了。这样就可以少写一个类了。
结果:
执行过程是这样的: 步骤1. 判断classmate是否是可迭代对象。因为Classmate类有__iter__方法,所以是可迭代对象。 步骤2. 如果是可迭代的,for循环会自动调用iter()函数,并传入classmate对象。iter(classmate)函数,会自动classmate对象的__iter__()方法,得到返回值。 步骤3. iter(classmate)函数的返回值要求是self。因为classmate有__iter__方法和__next__()方法,所以是一个迭代器。 步骤4. 返回了迭代器classmate之后,for每次循环就调用一次next(classmate)函数。next(classmate)函数会自动调用迭代器classmate的__next__()方法,得到一个结果。 每for一次,就会调用一次next,next返回什么就用什么。。
五、迭代器的应用
5.1 字符串、列表、元组、字典、集合不是迭代器,是可迭代对象。
结果:
5. 2 zip、enumerate 等itertools里的函数是迭代器
例1:
例2:
结果:
5. 3 文件是一个迭代器
结果:
5.4 range()不是迭代器
range()函数很特别,不是迭代器。具有序列的性质。【例1】 迭代器可以被耗尽,而range()不会。【例2】【例3】
range()不是迭代器,也不是一个序列。但是又有迭代器和序列的性质。那range()是个什么东西呢? 我们称range()是一个懒序列。range()是一个序列类型。但里面又不包括任何内容,并不是显示存储的。它是通过计算来回答的。
例1:
结果:
例2:迭代器可以耗尽
结果:
例3:
结果:
|