爬虫日记之08迭代器和可迭代对象的理解
2022-3-6
1 写在前面
首先我们回顾一下在C语言中我们是如何遍历数组以及链表的~
遍历数组:
for (int i=0;i<sizeof(arrTest)/sizeof(int);i++)
{
printf("%d\n",arrTest[i])
}
遍历链表:
NODE p=Head->next;
while(p)
{
printf("%d ",p->data);
p=p->next;
}
我们把数据和链表形象的看做“数据容器”,为了达到遍历的目的,我们需要访问容器中的每一个元素,而C语言这样的写法却很容易出现很多问题:
- 针对不同的数据容器,采取的写法完全不同,可嫁接性低(自创词汇😁),也不利于书写和阅读;
- 对编程者要求较高。比如只要循环条件写错了一点点,都会导致遍历功能无法实现
好的现在压力来到了新生代编程语言,以python为例,python是如何解决这个问题的呢?
那就让我们走进今天的主人公——迭代器。
2 迭代器的使用
首先我们来回顾一下在python中,我们是如何进行遍历操作的:
# 遍历列表
for e in List1:
print(e)
# 遍历字典
for e in dic1:
print(e)
# 遍历文件内容
for e in open("test.txt"):
print(e)
我们可以惊喜地发现(强行惊喜🤷♀️),python中不同数据容器的遍历写法相同,更有利于我们的书写的理解。
而for语句之所以可以如此“万能”,正是因为背后有迭代器在默默地支持。
for语句在执行的时候,会在背后做两件事。
- 第一件事,就是调用“数据仓库”位置对象的__iter__()方法;
- 第二件事,把__iter()__ 方法的返回值当成一个对象,并且调用这个对象的__next__()方法;
在python中通过迭代器,我们可以使用相同的代码,对不同的数据容器进行遍历
列表、字典、文件都可以作为迭代器
我们可以通过代码查看某个对象是不是可迭代的
方法一
先对a进行定义,通过在a后加上.的方式,看该对象有无:对象.iter()的形式
a=2333
a._iter_()
#通过观察是否报错来查对象a是否可以迭代
#也可以通过强行代入for语句来判断
方法二
使用isinstance方法来进行判断
from collections.abc import Iterable
a=2333
isinstance(a,Iterable)
list1=[1,2,3]
isinstance(list1,Iterable)#判断list1对象是否为可迭代对象
isinstance(list1,Iterator)#判断list1是否为迭代器
3 迭代器、生成器和可迭代对象
3.1 迭代器
3.1.1 迭代器类型的定义:
- 当类中定义了__iter__和__next__两个方法
- __iter__方法需要返回对象本身,即:self
- __next__方法,返回下一个数据,如果没有数据了,就需要弹出异常处理的语句
3.1.2 创建迭代器类型:
class IT(object):
def __init__(self):
self.counter=0
def __iter__(self):
return self
def __next__(self):
self.counter+=1
if self.counter==3:
raise StopIteration()
return self.counter
3.2 生成器
3.2.1 生成器类型的定义:
刚才我们介绍了什么是迭代器,其实生成器本质上也是一种迭代器,不过他的创建方式简单一些,可以分为以下两步:
- 类中需要定义一个以yield关键字标识返回值的函数
- 调用刚刚创建的函数,即可创建一个生成器
3.2.2 创建生成器函数
def func():
yield 1
yield 2
3.2.3 创建生成器对象
生成器内部是根据生成器类generator创建的对象,生成器类的内部也表明了__iter__、__next__方法。
obj1=func()
#此处obj1即为生成器对象
3.3 可迭代对象
如果一个类中有__iter__方法且返回一个迭代器对象,我们就称这个类创建的对象为可迭代对象。
3.3.1 可迭代对象的创建
class Foo(object):
def __iter__(self):
return 迭代器对象(生成器对象)
obj=Foo() # 可迭代对象
for item in obj:
print(item)
# 循环可迭代对象时,内部先执行obj.__iter__并获取迭代器对象,然后不断地执行迭代器对象的next方法
3.4 一个小演示
如图,我们先创立了一个整数列表,然后通过dir()函数查看v1中的成员,我们可以看到出现了__iter__方法,而并没有__next__方法。
然后我们继续对v1进行iter()操作,命名为v2,继续通过dir()函数查看v2中的成员,我们可以找到__iter__方法和__next__方法。
说明v2是一个迭代器对象,而v1是一个可迭代对象。
写在后面
让自己写的类支持迭代:
- 给类加入__iter__()方法
- 上述方法返回的对象是迭代器(支持__iter__()和__next__())
含泪推荐良心视频呜呜呜呜到底啥是迭代器?(官方文档证明,彻底搞懂迭代器)