一、迭代器
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)