• day 14


    生成器

    生成器
      生成器的本质就是迭代器
    生成器的表现形式
      生成器函数
        生成器函数 —— 本质上就是我们自己写得函数
      生成器表达式
    生成器函数:
      含有 yield 关键字的函数就是生成器函数
      特点:
        调用函数的之后函数不执行,返回一个生成器
        每次调用 next 方法的时候会取到一个值
        直到取完最后一个,在执行 next 会报错

    从生成器中取值的几个方法
      1、next
      2、for
      3、数据类型的强制转换:占用内存 print(list(g))

    生成器函数

    我们先来看下普通函数

    def generator():
        print(1)
        return 'a'
    ret = generator()
    print(ret)

    接着来看生成器函数

    #只要含有yield关键字的函数都是生成器函数
    # yield 不能和 return 共用且需要写在函数内
    def generator():
        print(1)
        yield 'a'
    #生成器函数:在执行之后会得到一个生成器作为返回值
    ret = generator()   #此处的 ret 是一个生成器而不是值了
    print(ret)          #此处在同过原来的调用方法调用的是内存地址
    print(ret.__next__())   #通过 .__next__() 来调用函数的输出内容

    下面来看一个生成器函数的例子

    #在取值时 会取到第一个 yield 时停止,然后等待下一次取值的动作开始,继续取值到下一个 yield 
    def generator():
        print(1)
        yield 'a'
        print(2)
        yield 'b'
        print(3)
        yield 'c'
    g = generator()
    
    ret = g.__next__()  #单独执行第一次时:1 a
    print(ret)
    ret = g.__next__()  #即:可以控制执行的位置
    print(ret)
    ret = g.__next__()
    print(ret)
    
    for i in g:         #使用 for 循环也同样可以
        print(i)        #但 for 循环不可以控制执行位置

    写一个函数 制造 200w 个娃哈哈

    ef wahaha(*args):
        for i in range(2000000):
            yield "娃哈哈%s"%i
    ret = wahaha(1000)
    
    #调用
    #for i in ret:
    #    print(i)
    
    #调用前 50 个
    count=0
    for i in ret:
        print(i)
        count+=1
        if count > 50:
            break
    print(ret.__next__()) #这里一起执行会接着 for 循环调用 ret ,返回第 51个

    监听文件输入的例子

    #当检查到文件中有输入含有 python 字符时就会在屏幕上打印
    def tail(filename):
        f = open(filename,encoding='utf-8')  #文件句柄
        while True:
            line = f.readline()
            if line.strip():
                yield line.strip()
    
    ret = tail('D:/py/log/test.txt')
    for i in ret:
        if 'python' in i:
            print('***',i)

    生成器函数进阶

    关键字 send 的使用

    #send 获取下一个值的效果和 next 基本一致
    #只是在获取下一个值的时候,给上一 yield 的位置传递一个数据
    #使用 send 的注意事项
        # 使用生成器取第一个值的时候 必须用 next 来取值
        # 最后一个 yield 不能接受外部的值
    
    def generator():
        print(123)
        content = yield 1
        print('=====',content)
        print(456)
        yield 2
    
    g = generator()
    ret = g.__next__()
    print('***',ret)
    ret = g.send('hello')  #向函数 content 的位置传值
    print('***',ret)

    获取移动平均值(每次输入一个值都会计算出一个平均值)

    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 = average()
    avgs = avg.__next__()
    avgs = avg.send(10)
    avgs = avg.send(30)
    avgs = avg.send(60)
    avgs = avg.send(60)
    print(avgs)

    预激生成器的装饰器
    获取移动平均值进阶与装饰器的使用

    #装饰器的作用就是在用户使用时,少写一句 ret = g.__next__() 方便操作
    def init(func):
        def inner(*args,**kwargs):
            ret = func(*args,**kwargs)
            ret.__next__()
            return ret
        return inner
    
    
    @init
    def average():
        sum =0
        count = 0
        avg = 0
        while True:
            num = yield avg
            sum += num
            count += 1
            avg=sum/count
            
    avg = average()
    ret = avg.send(10)
    ret = avg.send(20)
    ret = avg.send(60)
    print(ret)
    ret = avg.send(20)
    ret = avg.send(20)
    print(ret)

    from 关键字的使用

    #先来看一个 for 循环的例子,取出字符串中所有的单个字符
    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)
    
    #使用 from 关键字取出
    def generator():
        a = 'abcde'
        b = '12345'
        yield from a
        yield from b
    
    g = generator()
    for i in g:
        print(i)

    生成器的表达式

     来看简单的生成器表达式的例子

    g = (i for i in range(10)) 
    ret = g.__next__()
    print(ret)
    
    for i in g:
        print(i)
    
    
    老母鸡=('鸡蛋%s'%i for i in range(10)) #生成器表达式
    print(老母鸡)
    forin 老母鸡:
        print(蛋)
    
    
    g = (i*i for i in range(10))
    g.__next__()
    for i in g:
        print(i)
    
    
    '''
    生成器表达式与列表推导式的区别
    1、括号不一样(列表为:[],生成器为:())
    2、返回的值不一样 === 几乎不占用内存
    '''

    各种推导式

    包括:生成器 列表 字典 集合

    生成器表达式与列表表达式语法一样 换个括号基本就 ok

    作用:遍历操作、筛选操作
    [每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] —— 遍历之后挨个处理
    [满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件] —— 筛选功能

    列表推导式例子

    # 30以内所有能被3整除的数
    ret = [i for i in range(30) if i%3 == 0]
    print(ret)
    
    # 30以内所有能被3整除的数的平方
    g = [i*i for i in range(30) if i%3 ==0]
    print(g)
    
    '''
    
    # 找到嵌套列表中名字含有两个‘e’的所有名字
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
             ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    e = [name for lis in names for name in lis if name.count('e') == 2]
    print(e)

    字典推导式例子

    #例一:将一个字典的key和value对调 效果:{10:'a' , 34:'b'}
    mcase = {'a': 10, 'b': 34}
    mcase_frequency = {mcase[k]: k for k in mcase}
    print(mcase_frequency)
    
    # 例二:合并大小写对应的value值,将k统一成小写,效果:{'a':10+7,'b':34,'z':3}
    mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
    mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase}
    print(mcase_frequency)

    集合推导式

    #集合推导式,自带结果去重功能
    squared = {x**2 for x in [1, -1, 2]}
    print(squared)
  • 相关阅读:
    OSG绘制几何图形
    OSGMFC
    OSG第一个Demo
    线性四叉树十进制Morton码计算示例
    单源最短路径——Dijkstra算法学习
    .Net内存优化的几点经验
    强制回收和IDisposable.Dispose方法
    七参数计算正确性验证——Coord软件使用
    [转载]windows任务管理器中的工作设置内存,内存专用工作集,提交大小详解
    T4自动生成数据库C#实体类学习(1)
  • 原文地址:https://www.cnblogs.com/ysging/p/10089807.html
Copyright © 2020-2023  润新知