10_Python生成器_全栈开发学习笔记

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的注意事项

  1. 第一次使用生成器的时候 是用next获取下一个值
  2. 最后一个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 列表推导式与生成器表达的不同

  1. 括号不一样
  2. 返回的值不一样 === 生成器表达式的优点几乎不占用内存

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 条件)

你可能感兴趣的:(10_Python生成器_全栈开发学习笔记)