1. 生成器开篇
生成器 —— 生成器的本质还是迭代器(自己写的)
生成器函数 —— 本质上就是我们自己写得函数
2. 生成器函数
范例1:
普通函数的例子
def generator():
print(1)
return 'a'
ret = generator()
print(ret)
执行结果:
1
a
范例2:
生成器函数的例子
只要含有yield关键字的函数都是生成器函数
yield不能和return共用且需要写在函数内
# 只要含有yield关键字的函数都是生成器函数
# yield不能和return共用且需要写在函数内
def generator(): # 第一步
print(1) # 第六步
yield 'a' # 第七步
# 生成器函数 : 执行之后会得到一个生成器作为返回值
ret = generator() # 第二步 # 第三步
print(ret) # 第四步
print(ret.__next__()) # 第五步
执行结果:
1
a
范例3.1:
将yield作为return返回值出现的例子
def generator():
print(1)
yield 'a'
print(2)
yield 'b'
yield 'c'
g = generator()
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)
执行结果:
1
a
2
b
c
范例3.2
直接用for循环执行
def generator():
print(1)
yield 'a'
print(2)
yield 'b'
yield 'c'
g = generator()
for i in g:
print(i)
执行结果:
1
a
2
b
c
范例4.1:
娃哈哈%i(两百万个哇哈哈)
def wahaha():
for i in range(2000000):
yield "哇哈哈%s"%i
g = wahaha()
for i in g:
print(i)
执行结果:
...
哇哈哈586620
哇哈哈586621
哇哈哈586622
...
范例4.2:
只调取5个哇哈哈
def wahaha():
for i in range(2000000):
yield "哇哈哈%s"%i
g = wahaha()
count = 0
for i in g:
count += 1
print(i)
if count > 50:
break
执行结果:
...
哇哈哈47
哇哈哈48
哇哈哈49
哇哈哈50
范例4.3:
调取5个后继续执行一次
def wahaha():
for i in range(2000000):
yield "哇哈哈%s"%i
g = wahaha()
count = 0
for i in g:
count += 1
print(i)
if count > 5:
break
print("******",g.__next__())
执行结果:
哇哈哈0
哇哈哈1
哇哈哈2
哇哈哈3
哇哈哈4
哇哈哈5
****** 哇哈哈6
范例4.4:
5个之后再调取5个
def wahaha():
for i in range(2000000):
yield "哇哈哈%s"%i
g = wahaha()
count = 0
for i in g:
count += 1
print(i)
if count > 5:
break
#print("******",g.__next__())
for i in g:
count += 1
print(i)
if count > 10:
break
执行结果
哇哈哈0
哇哈哈1
哇哈哈2
哇哈哈3
哇哈哈4
哇哈哈5
哇哈哈6
哇哈哈7
哇哈哈8
哇哈哈9
哇哈哈10
2.1 监听文件输入的例子
#-*- encoding:utf-8 -*-
def tail(filename):
f = open(filename,encoding='utf-8')
while True:
line = f.readline()
if line.strip():
yield line.strip()
g = tail('file')
for i in g:
if 'python' in i:
print('***',i)
执行结果:
*** python
*** hello python
文件file内容:
dfsfsd
sdfsdf
s
dfds
f
ds
f
dsf
sf
python
hello python
3 从生成器中取值的三个方法
3.1 方法一:next
范例:
def generator():
for i in range(2000000):
yield "哇哈哈%s"%i
g = generator() # 调用生成器函数,得到一个生成器
ret = g.__next__() # 每一次执行g.__next__就是从生成器中取值,预示着生成器函数中的代码继续执行
print(ret)
执行结果:
哇哈哈0
3.2 方法二:for
范例:
def generator():
for i in range(2000000):
yield "哇哈哈%s"%i
g = generator() # 调用生成器函数,得到一个生成器
ret = g.__next__() # 每一次执行g.__next__就是从生成器中取值,预示着生成器函数中的代码继续执行
print(ret)
# 以下为方法二
num = 0
for i in g:
num += 1
if num > 5:
break
print(i)
执行结果:
哇哈哈0
哇哈哈1
哇哈哈2
哇哈哈3
哇哈哈4
哇哈哈5
3.3 数据类型的强制转换 : 占用内存
def generator():
for i in range(10):
yield "哇哈哈%s"%i
g = generator() # 调用生成器函数,得到一个生成器
print(list(g))
执行结果:
['哇哈哈0', '哇哈哈1', '哇哈哈2', '哇哈哈3', '哇哈哈4', '哇哈哈5', '哇哈哈6', '哇哈哈7', '哇哈哈8', '哇哈哈9']
4 生成器函数进阶
4.1 使用生成器的方式一
范例:
def generator():
print(123)
yield 1
print(456)
yield 2
print(789)
g = generator()
ret = g.__next__()
print("***",ret)
ret = g.__next__()
print("***",ret)
执行结果:
123
*** 1
456
*** 2
4.2 使用生成器的方式二
范例1:
def generator():
print(123)
yield 1
print(456)
yield 2
print(789)
g = generator()
ret = g.__next__()
print("***",ret)
ret = g.send(None) # send的效果和next一样
print("***",ret)
执行结果:
123
*** 1
456
*** 2
范例2:
def generator():
print(123)
content = yield 1
print("======",content)
print(456)
yield 2
print(789)
g = generator()
ret = g.__next__()
print("***",ret)
ret = g.send("hello") # send的效果和next一样
print("***",ret)
执行结果:
123
*** 1
====== hello
456
*** 2
结论:
send 获取下一个值的效果和next基本一致
只是在获取下一个值的时候,给上一个yield的位置传递一个数据(第一次不能用send)
使用send的注意事项
- 第一次使用生成器的时候 是用next获取下一个值
- 最后一个yield不能接受外部的值
4.3 生成器进阶实例
实例1.1:
获取移动平均值1
# 总数:10 20 30 10
# 平均:10 15 20 17.5
# avg = sum/count
def average():
sum = 0
count = 0
avg = 0
while True:
num = yield avg
sum += num
count += 1
avg = sum/count
avg_g = average()
avg_g.__next__()
avg1 = avg_g.send(10)
avg1 = avg_g.send(20)
avg1 = avg_g.send(60)
print(avg1)
执行结果:
30.0
实例1.2:
获取移动平均值2(预激生成器的装饰器)
def init(func): #装饰器
def inner(*args,**kwargs):
g = func(*args,**kwargs) #g = average()
g.__next__()
return g
return inner
@init
def average():
sum = 0
count = 0
avg = 0
while True:
num = yield avg
sum += num # 10
count += 1 # 1
avg = sum/count
avg_g = average() #===> inner
ret = avg_g.send(10)
print(ret)
ret = avg_g.send(20)
print(ret)
执行结果:
10.0
15.0
5 生成器函数额外的知识点
介绍python3的新功能
范例1.1:普通例子
def generator():
a = 'abcde'
b = '12345'
for i in a:
yield i
for i in b:
yield i
g = generator()
for i in g:
print(i)
执行结果:
a
b
c
d
e
1
2
3
4
5
范例1.2:
python3新功能:yield from
def generator():
a = 'abcde'
b = '12345'
yield from a
yield from b
g = generator()
for i in g:
print(i)
执行结果:
a
b
c
d
e
1
2
3
4
5
6 生成器的表达式
6.1 列表推导式
范例1.1:普通方式
egg_list = []
for i in range(10):
egg_list.append("鸡蛋%s"%i)
print(egg_list)
执行结果:
['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
范例1.2:列表推导式
egg_list = ["鸡蛋%s"%i for i in range(10)]
print(egg_list)
执行结果:
['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
范例2:
列表推导式语法
[每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] #遍历之后挨个处理
范例:
print([i for i in range(10)])
print([i*2 for i in range(10)])
print([i*i for i in range(10)]) # 平方
执行结果:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
6.2 生成器表达式
范例1:
g = (i for i in range(10))
print(g) # g就是生成器
for i in g:
print(i)
执行结果:
at 0x0000022EE1C546D0>
0
1
2
3
4
5
6
7
8
9
范例2:老母鸡下蛋
老母鸡 = ("鸡蛋%s"%i for i in range(10)) # 生成器表达式
print(老母鸡)
for 蛋 in 老母鸡:
print(蛋)
执行结果:
at 0x000001C2549346D0>
鸡蛋0
鸡蛋1
鸡蛋2
鸡蛋3
鸡蛋4
鸡蛋5
鸡蛋6
鸡蛋7
鸡蛋8
鸡蛋9
范例3:额外例子
g = (i*i for i in range(10))
g.__next__()
6.3 列表推导式与生成器表达的不同
- 括号不一样
- 返回的值不一样 === 生成器表达式的优点几乎不占用内存
7 各种推导式
7.1 列表推导式
语法:
[每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] #遍历之后挨个处理
[满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件] #筛选功能
范例1:
30以内所有能被3整除的数
ret = [i for i in range(30) if i%3 == 0] #完整的列表推导式
# ret = (i for i in range(30) if i%3 == 0) # 变成生成器表达式
print(ret)
执行结果:
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
范例2:
30以内所有能被3整除的数的平方
ret = [i*i for i in range(30) if i%3 == 0]
# ret = (i*i for i in range(30) if i%3 == 0) # 变成生成器表达式
print(ret)
执行结果:
[0, 9, 36, 81, 144, 225, 324, 441, 576, 729]
范例3:
找到嵌套列表中名字含有两个"e"的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
ret = [name for lst in names for name in lst if name.count("e") == 2]
# ret = (name for lst in names for name in lst if name.count("e") == 2) # 变成生成器表达式
print(ret)
执行结果:
['Jefferson', 'Wesley', 'Steven', 'Jennifer']
7.2 字典推导式
范例1:
将一个字典的key和value对调
mcase = {'a': 10, 'b': 34}
#{10:'a' , 34:'b'}
mcase_frequency = {mcase[k]: k for k in mcase}
print(mcase_frequency)
执行结果:
{10: 'a', 34: 'b'}
范例2:
合并大小写对应的value值,将k统一成小写
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
#{'a':10+7,'b':34,'z':3}
mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase}
print(mcase_frequency)
执行结果:
{'a': 17, 'b': 34, 'z': 3}
7.3 集合推导式
范例:
计算列表中每个值的平方,自带去重功能
squared = {x**2 for x in [1, -1, 2]}
print(squared)
执行结果:
{1, 4}
8 生成器复习
# 生成器 —— 迭代器
# 生成器函数
# 含有yield关键字的函数都是生成器函数
# 生成器函数的特点
#调用之后函数内的代码不执行,返回生成器
#每从生成器中取一个值就会执行一段代码,遇见yield就停止。
#如何从生成器中取值:
# for :如果没有break会一直取直到取完
# next :每次只取一个
# send :不能用在第一个,取下一个值的时候给上个位置传一个新的值
# 数据类型强制转换 :会一次性把所有数据都读到内存里
# 生成器表达式
# (条件成立想放在生成器中的值 for i in 可迭代的 if 条件)