zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    heat模板
    Leetcode812.Largest Triangle Area最大三角形面积
    Leetcode812.Largest Triangle Area最大三角形面积
    Leetcode811.Subdomain Visit Count子域名访问计数
    Leetcode811.Subdomain Visit Count子域名访问计数
    Leetcode806.Number of Lines To Write String写字符串需要的行数
    Leetcode806.Number of Lines To Write String写字符串需要的行数
    Leetcode819.Most Common Word最常见的单词
    Leetcode819.Most Common Word最常见的单词
    Leetcode783.Minimum Distance Between BST Nodes二叉搜索树结点最小距离
  • 原文地址:https://www.cnblogs.com/ysging/p/10089807.html
Copyright © 2011-2022 走看看