写点什么

二十、深入 Python 迭代器和生成器

用户头像
刘润森
关注
发布于: 2020 年 10 月 21 日
二十、深入Python迭代器和生成器

@Author: Runsen



学习python的过程中,迭代器与生成器是绕不开的话题, 什么是迭代器和生成器呢?



下面我们来了解一下什么是迭代。但在了解迭代器之前,首先需要知道什么是容器。



容器



正所谓:一切都是对象,对象的抽象就是类,而对象的集合就是容器。



容器,就是有多个对象组成的东西。



比如:列表[0,1,2],元组(1,2,3),字典{’0:'0','1':"1'}集合{1,2,3}都是容器。



所有的容器都是可迭代对象,也就是可以使用for循环遍历元素。



# 1、for 循环迭代字符串, 字符串之间使用空格连接
for char in 'RUNSEN':
print(char, end=' ')
输出如下:
R U N S E N

# 2、for 循环迭代 list 列表,列表元素之间使用空格连接
list1 = [i for i in range(5)] # 这里使用了列表生成表达式
for num in list1:
print(num, end=' ')
输出如下:
0 1 2 3 4

# 3、for 循环迭代 dict (字典)
dict = {'name': 'Runsen', 'age': '21', 'sex': '男'}
# 迭代 dict 中的 key(默认是迭代key)
for key in dict:
print(key, end=' ')

for value in dict.values():
print(value, end=' ')

输出如下:
name age sex
Runsen 21 男

# 4、list 中一个元素中还有多个元素
for x, y in [(1, 'a'), (2, 'b'), (3, 'c')]:
print(x, y)
输出如下:
1 a
2 b
3 c



可迭代对象



所有的容器都是可迭代对象(iterable),从专业角度来讲,只要:内部含有__iter__方法的对象,就是可迭代对象。



因此,我只要使用print('__iter__' in dir(XX)),就能判断XX是不是可迭代对象。



人们常说:列表、元组、字典、字符串都是可迭代对象。数字、布尔值都是不可迭代的。我一试便知。



list,dict(keys(),values(),items()),tuple,str,set,range, 文件句柄(待定)



print('__iter__' in dir(list))
print('__iter__' in dir(tuple))
print('__iter__' in dir(dict))
print('__iter__' in dir(set))
print('__iter__' in dir(str))
print('__iter__' in dir(int))
print('__iter__' in dir(bool))
print('__iter__' in dir([1,2,3]))


输出如下:
True
True
True
True
True
False
False
True




除了print('__iter__' in dir(XX))判断是不是可迭代对象。还是一种通过Iterableisinstance方法联合使用,进行判断。



from collections import Iterable

print(isinstance('abc', Iterable))
print(isinstance({1, 2, 3}, Iterable))
print(isinstance(1, Iterable))

输出如下:
True
True
False



注意:list,string,tuple,dict 都属于可迭代对象,但不是迭代器



迭代器



迭代器(iterator)只是提供了一个 next 的方法。调用这个方法后,你要么得到这个可迭代对象的下一个对象,要么得到一个 StopIteration 的错误。



那么,如何声明一个可迭代对象,可以通过__iter__() 来生成可迭代对象,前提是__iter__()传入的参数是容器。



你看下图iter(111)是不是报错了。





因为111不能遍历,所以iter(111)直接报错。



取值



上面说过:迭代器提供了一个next方法,调用这个方法,得到了容器的下一个对象或者一个stopiteration 的报错,具体代码如下所示。



>>> a = iter("123")
>>> next(a)
'1'
>>> next(a)
'2'
>>> next(a)
'3'
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration



生成器



那么什么又是生成器,和迭代器又有什么关系?



其实,生成器也是迭代器,但更加优雅。使用生成器,我们可以实现与迭代器相同的功能,但不必在类中编写iter()和next()函数



我觉得生成器就是一个迭代器的例子。,如果说迭代器是人,那么生成器就人中的一类人,比如黄人。



为什么会出来一个生成器,其实很简单声明一个迭代器很简单,但是很容易造成内存不够。生成器不会将集合中所有的元素都加载到内存。



比如下图(i for i in range(1000000000)通过元组方式生成生成器。如果使用迭代器,那么当声明迭代器就运行不了了。







[i for i in range(1000000000] 它本是一个迭代器,但因占用的内存太大了,跑不起来,于是古人引出了生成器的概念,当你用的时候,再加载到内存空间中。



在声明生成器中,还有一种方法通过yield关键字。



yieldreturn的区别在于yield并没有终止函数,而return返回值后不再执行函数内代码。



对于yield,在scrapy用的多,然后我在其他地方没有见到过。



引用yield,带yield的函数就叫做生成器,具体示例如下所示。



def test():
yield 1
yield 2
yield 3
t = test()

print(next(t))#output:1
print(next(t))#output:2
print(next(t))#output:3
print(next(t))#output:Traceback (most recent call last):StopIteration



今天也学到了很多东西呢,明天有什么新知识呢?真期待鸭~如果喜欢文章可以关注我哦~



本文已收录 GitHub,传送门~ ,里面更有大厂面试完整考点,欢迎 Star。



发布于: 2020 年 10 月 21 日阅读数: 29
用户头像

刘润森

关注

刘润森 2018.09.17 加入

17年就读于东莞XX学院化学工程与工艺专业,GitChat作者。Runsen的微信公众号是"Python之王",关注后回复「小白」即可免费获取原创的Python学习资料;喜欢的微信搜索:「Python之王」。个人微信号:RunsenLiu

评论

发布
暂无评论
二十、深入Python迭代器和生成器