python之迭代器、生成器
一、迭代器
1、什么是迭代器
迭代器就是迭代取值的工具,什么是迭代呢?
迭代是一个重复的过程,但是每一次重复都是基于上一次的结果而来,这就是迭代
# 循环重复,但是每一次没有关联,不是迭代 while True: print("111") # 循环重复,但是每次循环基于上次,是迭代 x = 0 while True: print(x) x += 1
2、为什么要用迭代器
我们之前有讲过,列表、元组等可以通过索引取值,字典可以通过key取值,但是这些都是他们自身的特性,其他数据类型无法使用,那有没有一种统一的方法进行取值呢?
这就要用到迭代器,基于以下两个原因:
- 为了能找到一种新的、统一的取值方式(可以不依赖与索引与key取值)
- 惰性计算,不耗费内存(当数据很大时,列表、字典等会占据很大的内存)
3、如何使用迭代器
1)可迭代对象
从语法形式上讲,内置有__iter__方法的对象都是可迭代对象,字符串、列表、元组、字典、集合、打开的文件都是可迭代对象:
# 带有内置方法__iter__(),都是可迭代对象 [1, 2, 3, 4, 5].__iter__() "safdsdsf".__iter__() {"name": "zhang"}.__iter__() {1, 2, 3, 4, 5, 6}.__iter__()
2)迭代器对象
任何可迭代对象调用iter()方法后,都会生成一个迭代器对象,迭代器对象内置有__iter__与__next__方法,当调用__iter__方法后,返回的还是迭代器自身,而调用__next__方法后,迭代器会根据迭代对象生成以一个值,再调用__next__,就会生成下一个值,从第一个开始顺序取值,一旦值取完就会报错,过程不可逆不可改变顺序,并且取完值后,迭代器无法再次取值。
通俗说法:迭代器就像一只能下蛋的母鸡,我们想要的是母鸡肚子里的蛋,我们调用一下__next__,母鸡就下一个蛋,当母鸡把蛋下完,老母鸡炖汤,就在也无法得到蛋了,除非再造一只老母鸡
x = [1,2,3,4,5].__iter__() # 使用__iter__()方法会得到一个返回值:迭代器对象 # 一般情况下,我们使用iter()得到迭代器对象而不是__iter__() x = iter([1,2,3,4,5]) # y = x.__next__() # 生成第一个值,并且返回该值 y1 = next(x) # 与__next__一致,但是常用next() y2 = next(x) # 取得第二个数 y3 = next(x) # 取得第三个数 y4 = next(x) # 取得第四个数 y5 = next(x) # 取得第五个数 print(y1,y2,y3,y4,y5) y6 = next(x) # 取第六个数,但是不存在,报错
3)for循环原理:for循环的本质,就是调用了iter()方法得到一个迭代器对象,然后调用next()方法逐个取值,知道取完为止
#使用for循环实现遍历取值 str1 = [1, 2, 3, 4, 5] str_iter = iter(str1) while True: try: x = next(str_iter) print(x) except StopIteration: break # for循环等价于上诉的过程 for i in str1: print(i)
4)如果使用for循环读迭代器对象取值,结果如何?
str1 = [1,2,3,4] # 可迭代对象 str_iter = iter(str1) # 迭代器对象 # 使用for循环对迭代器对象取值 for i in str_iter: print(i) for j in str_iter: print(j) print("*"*20) # 使用for询函对可迭代对象取值 for i in str1: print(i) for j in str1: print(j)
运行结果如下:

可以看到,如果使用迭代器对象,只能遍历取值1次,下一次就无法取到任何值,但是使用可迭代对象,确实可以取值多次。这是因为迭代器对象是“一次性”,取完一次就无法取 值,而使用可迭代对象,for循环每次都会造一个迭代器对象,所以可以多次取值。
5)迭代器总结
优点:
1、为序列和非序列类型提供了一种统一的迭代取值方式。
2、惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用next来计算出一个值,就迭代器本身来说,同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,如列表,需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的。
缺点:
1、除非取尽,否则无法获取迭代器的长度
2、只能取下一个值,不能回到开始,更像是‘一次性的’,迭代器产生后的唯一目标就是重复执行next方法直到值取尽,否则就会停留在某个位置,等待下一次调用next;若是要再次迭代同个对象,你只能重新调用iter方法去创建一个新的迭代器对象,如果有两个或者多个循环使用同一个迭代器,必然只会有一个循环能取到值
二、生成器
1、什么生成器?
1)如果函数体内出现了yield关键字,那么当在调用函数时,函数不会执行函数体代码,而是生成一个生成器。
生成器的实质就是一种自定义的迭代器
# 生成器 def f1(start, end): while start < end: yield start # 当函数运行到此处就停止运行,等待调用next(),逐个取值,直到值取完报错 start += 1 x = f1(0, 4) # 得到生成器对象 print(f1(0, 4)) print(next(x)) # 调用next方法取值 print(next(x)) print(next(x)) print(next(x)) # print(next(x)) # 超过了四个,这里会报错
2)生成器与for循环:作为一种迭代器对象,生成器也是可以使用for循环遍历,
def f1(start, end): while start < end: yield start # 当函数运行到此处就停止运行,等待调用next(),逐个取值,直到值取完报错 start += 1 f = f1(0,5) # 得到迭代器对象 for i in f: # for循环遍历 print(i) print("*"*20) # 分隔 for j in f: # 再次遍历上述迭代器对象 print(j)
注意这里是迭代器对象,只能被for循环取值1次
3)生成器与send()方法
send()方法可以拿到函数的生成器对象持续为函数体send值
def eater(): print('Ready to eat') while True: food = yield "start" print('get the food: %s, and start to eat' % food) g = eater() # 这里拿到生成器对象 print(g) next(g) # 在我们传值之前,需要初始化生成器对象,让生成器在food = yiel处挂起,等待传值 g.send("狗屎") # 将"狗屎”赋值到food,然后打印,下次循环到ood = yiel处挂起,等待传值 g.send("猿粪")# 同上层
表达式形式的yield也可以用于返回多次值,即 变量名 = yield 值 的形式
def cooker(): list1 = [] while True: list2 = yield list1 list1.append(list2) print(list1) a = cooker() # 获得生成器对象 next(a) # 初始化生成器 a.send("西瓜汁") a.send("苹果汁")
运行过程
- 通过赋值,得到生成器对象a
- next(a),初始化生成器,运行到list2 = yield list1处,返回list1(初始值[]),等待next(),或send()传值
- 通过a.send(“西瓜汁”)方法,向生成器对象传值,此时,"西瓜汁”被传入生成器,并且赋值给list2,运行列表增加,打印list1(添加了西瓜汁),进入下一次循环
- 第二次循环,再次返回list1([“西瓜汁”]),等待next(),或send()传值;
- 通过a.send(“苹果汁”)方法,向生成器对象传值,此时,"苹果汁”被传入生成器,并且赋值给list2,运行列表增加,打印list1(添加了西瓜汁、苹果汁),进入下一次循环
- .....如此循环
二、三元表达式
三元表达式是python为我们提供的一种简化代码的解决方案,语法如下
res = 条件成立时返回的值 if 条件 else 条件不成立时返回的值
# 三元表达式 x = 5 y = 8 if x < y: print(x) else: print(y) # res = 条件成立时返回的值 if 条件 else 条件不成立时返回的值 res = print(x) if x < y else print(y) # 等价于上述if判断语句
三、列表生成式
列表生成式是python为我们提供的一种简化代码的解决方案,用来快速生成列表,语法如下
[expression for item1 in iterable1 if condition1 for item2 in iterable2 if condition2 ... for itemN in iterableN if conditionN ] #类似于 res=[] for item1 in iterable1: if condition1: for item2 in iterable2: if condition2 ... for itemN in iterableN: if conditionN: res.append(expression)
实例:
list1 = [] for i in range(0,10): if i % 2 == 1: list1.append(i) print(list1) list1 = [i for i in range(0,10) if i % 2 == 1] # 等价于上述for循环 print(list1)
四、字典生成式
dic1 = {} for i in range(1,10): if i < 6: dic1["number"] = i print(dic1) # 等价于上述for循环 dic1 = {"number":i for i in range(1,10) if i < 6} print(dic1)
五、生成器表达式
产生生成器的两种方式:
- 函数+yiel
- 生成器表达式:()
(expression for item in iterable if condition)
实例:
f1 = (i for i in range(0,5) if i > 1) print(f1) print(next(f1))
结果如下:
C:\Users\Python\Python35-32\python.exe E:/python/保存文件/next1/作业/迭代器.py
<generator object <genexpr> at 0x00638CF0>
2
读取大文件的正取打开方式:使用生成器表达式,节省内存空间
with open("hhhh.txt","rt",encoding="utf-8") as f: lines = (i for i in f.readlines()) x1 = next(lines) x2 = next(lines) x3 = next(lines) print(x1) print(x2) print(x3)

浙公网安备 33010602011771号