美文网首页
10_Python生成器_全栈开发学习笔记

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

作者: 豆行僧 | 来源:发表于2019-01-13 22:40 被阅读0次

    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__())    # 第五步
    

    执行结果:

    <generator object generator at 0x000001FF95B146D0>
    
    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)
    

    执行结果:

    <generator object <genexpr> at 0x0000022EE1C546D0>
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    

    范例2:老母鸡下蛋

    老母鸡 = ("鸡蛋%s"%i for i in range(10))    # 生成器表达式
    print(老母鸡)
    for 蛋 in 老母鸡:
        print(蛋)
    

    执行结果:

    <generator object <genexpr> 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生成器_全栈开发学习笔记

          本文链接:https://www.haomeiwen.com/subject/kvkrdqtx.html