前言
介绍
在python的学习中,我们通常会听到python三大神器着一说法,但是有的同学并不知道python三大神器是指哪三大神器,或许有的小伙伴听过而且学过python三大神器,但是由于时间的原因,其中的一些细节知识出现了遗漏,那么今天我们就给小伙伴们讲讲python的三大神器。
三大神器是哪三大
我们通常说的python三大神器是指迭代器,生成器和装饰器。
迭代器特点:
1.节省内存
迭代器在内存当中就相当于占了一个数据(元素)的内存。
2.惰性机制
不去调用next()或则__next__就不会出现下一个元素。
3.不能往回走,向前看
用过的数据回不去了,只能是nxet(),可以理解为单线程的,当然啦,如果你想重头开始,也不是不行,那么再去拿一个新的迭代器就可以了。
引入迭代器
我们假设一下,不能使用for循环的情况下,怎么对字符串,集合,元组,列表,字典进行循环遍历呢(for循环的本质其实就是迭代器,后面会讲到)?对于列表,字符串呢,我们就拿它的索引,对索引进行遍历(用while哈),但是到了集合这里呢,这个方法就行不通了,这时候有好奇的小伙伴会问,为什么了?因为集合的无序性导致了它不存在索引这一说,那我们硬要遍历就只能够将索引变为其他的数据类型了。这样子,很多小伙伴们都会感到不便利,在实践中十分的不爽。显然,用同一种方法进行循环会便利得多,既然索引循环遍历这一方法搞不定,又有没有其他的方法呢?python为了解决这一问题,就引入了我们今天的主角了,那就是迭代器(基于可迭代协议)。
ps
这里要注意哈,并不是所有的数据类型都遵守可迭代协议,譬如int类型就不遵守
for i in 123456789:
print(i)
这里的运行结果是
我们这里做个对比哈
for i in "123":
print (i)
这行代码的运行结果是
很明显哈,int类型那里标注了一个not iterable,而字符串那里可以正常运行。
那么在这里,很多小伙伴们又会有另一个疑问了,那我怎么知道谁是可迭代的,谁是不可迭代的啊?别急,让我来讲讲一个妙招:在python里面有一个工具叫做dir,这个dir有什么用呢,它可以知道我们所输入的数据类型能执行哪些操作。
字符串类型的有
print(dir(int))
int类型的有
print(dir(int))
__iter__就是可迭代的意思,字符串中有,但是int类型没有哈,所以int就不可以迭代(注意哈,bool类型也不可以迭代),下次,我们不清楚一种数据类型能否可以迭代,就可以使用这一种方法来看。
迭代器怎么用
正文
list=["python","ML","DL","Matlab"]
print(list.__iter__())
在这里头,我们创建了一个列表,列表里面有着四个字符串。我们采用了__iter__这一操作,让我们看看会发生些什么变化。
我们发现在这里,结果给出了一个地址。等等,有的同学会有疑问了,刚才不是说iter是迭代的意思吗,怎么现在又给出了一个地址了啊。小伙伴们,别慌哈,这里是用__iter__将我们传入的列表带到了一个迭代器的工具里头,那怎么才能够进行迭代呢,别急,这里我们只需加上__next__便可,顾名思义哈,next就是下一个,我们调用一次__next__,就会有一个项跑出来了,请小伙伴们看下面的代码:
list=["python","ML","DL","Matlab"]
a=list.__iter__()
print(dir(a))
在这里,我们能够发现所谓的迭代器是可以进行__next__这一个操作的,于是我们调用一下__next__着一可执行操作
list=["python","ML","DL","Matlab"]
a=list.__iter__()
b=a.__next__()
print(b)
执行结果为
注意哈,__next__一次只能出一项哈
如果想再出一项,那么就得再一次地调用__next__
list=["python","ML","DL","Matlab"]
a=list.__iter__()
b=a.__next__()
print(b)
b=a.__next__()
print(b)
其运行结果为:
想要多少,我们就调用几次__next__
此时,有的同学又会有个问题了,我调用五次呢,是不是又回到了一开始的哪一项呢
那话不多说,跑段代码试试吧:
list=["python","ML","DL","Matlab"]
a=list.__iter__()
b=a.__next__()
print(b)
b=a.__next__()
print(b)
b=a.__next__()
print(b)
b=a.__next__()
print(b)
b=a.__next__()
print(b)
运行结果为
这里我们可以看到运行结果中出现了一个词,叫做StopIteration,顾名思义就是停止了迭代,那么这就和上面的假设相反了。
那么怎么才能重头开始呢,答案也很简单哈,那就是再拿一个新的迭代器。
ps
有点同学会这样子写代码哈:
list=["python","ML","DL","Matlab"]
a=list.__iter__()
b=a.__next__()
n=0
while n<6:
print (b)
n+=1
注意这是不行的
运行结果会变成下面这个样子
因为这样啊,就相当于你每次都拿的是b运行的结果
更有同学是这样做的:
list=["python","ML","DL","Matlab"]
a=list.__iter__()
b=a.__next__()
n=0
while n<6:
print (b.__next__())
n+=1
注意哈,这样也是不行的
运行结果是会报错的
我们观察报错的原因就会发现,我们的b是字符串,并没有__next__这一可执行操作,感兴趣的小伙伴可以去执行一下dir这一查找操作。#可迭代对象没有__next__,迭代器可迭代(__iter__)
那么如果你想写一个循环,而不是一直地采用复制一下语句
b=a.__next__()
print(b)
那么你可以用下面的代码
list=["python","ML","DL","Matlab"]
n=0
a=list.__iter__()
while n<6:
print (a.__next__())
n+=1
这样看上去是不是简洁明了很多呢,那我们跑一下看看是不是和我们之前的结果是一样的
结果如下
for循环的内部工作机制
代码
我们一开始讲到假设不能用for循环会怎么样,那为什么加上这个前提条件后,会差别这么大呢?下面我们就来讲讲for循环的内部工作机制:
首先,我们讲讲for循环怎么用
list=["python","ML","DL","Matlab"]
for item in list:
print(item)
这就是普通的for循环了,我们跑一下
那这些求知欲爆棚的小伙伴们肯定不满足于此啊,那我们来拆开for循环,来看看它是怎么工作的
list=["python","ML","DL","Matlab"]
a=iter(list)
while True:
try:
print(next(a))
except StopIteration:
break
解释
来,我们跑一下这段代码
这就是for循环的内部机制了,看看运行结果是不是和刚才的是一样的?
try是指尝试一下,如果代码能够正常运行的话,那么就运行冒号后面的代码
那么try了一下不能正常运行,这可能是由很多原因导致的,如果导致错误的原因是StopIteration,即停止迭代,那么我们就执行except StopIteration后面的代码。
总结
步骤
step1:调用__iter__来拿到迭代器
step2:利用迭代器,调用__next__来拿到每一项元素
step3:重复step2,直到出现StopIteration
要注意的点
1.如果想再拿到第一个元素,那么请再拿一个迭代器
2.不能等价代换,譬如
list=["python","ML","DL","Matlab"]
print (list.__iter__().__next__())
print (list.__iter__().__next__())
print (list.__iter__().__next__())
print (list.__iter__().__next__())
print (list.__iter__().__next__())
运行结果如下
这里就是哐哐地在拿新的迭代器
简单版
list=["python","ML","DL","Matlab"]
a=iter(list)
print(next(a))
运行结果
注意看:这里我们使用了iter()和next()这两个函数,就不用像刚刚那样写__iter__和__next__了
来,我们再改改上面的循环代码,让它更简洁
list=["python","ML","DL","Matlab"]
n=0
a=iter(list)
while n<6:
print (next(a))
n+=1
运行结果是一样的哈。
谢谢各位小伙伴的阅读,不要忘了收藏点赞喔,顺便关注一下博主哦。