zoukankan      html  css  js  c++  java
  • 生成器 补充

    主要内容

    • 生成器
    • 生成器函数
    • 列表推导式
     什么是生成器: 本质就是迭代器
    在python中有三种方式来获取生成器:
    1 通过生成器函数
    2通过各种推导式来实现生成器
    3通过数据的转换也可以以(获取)生成器
    例子1
    def func():
        print(111)
        return 22
    a=func() # 111
    print(a) #222  #
     生成器函数

    retuurn和yield的关系:

        return是用来返回具体的某个值,yield一般与循环一起用,相当于生成了一个容器(常见的就是字典),
        然后在这个容器里面存放了每次循环以后的值,并且就在那放着,不输出,不返回,
        等你下次需要他的时候直接取出来用(调用)就行

    yield和__next__()的关系:

        yield关键字的特点: 可以记录当前函数中执行的位置,下一次继续执行
        next和yield是一对搭档 : next开始函数的执行 yield停止函数的执行

    例子2
    def func():
        print(111)
        yield 222
    ret=func()
    print(type(ret)) #<class 'generator'>   generator:生成器
    print(ret) # <generator object func at 0x00000148B4751D58>

    运行结果和上面不一样 由于函数中存在了yield,那么此时的函数就是一个生成器函数
    这个时候 再用函数的调用方法就不行了,此时该函数不执行,而是获得一个生成器
    想要执行此函数就可以直接__next__()来执行,因为生成器的本质就是迭代器.
    def func():
        print(111)
        yield 222# 函数遇到yiled会暂时停止和retun的区别在于 yiled是分段执行函数 return是直接停止函数
    
    ret=func()  # 函数此时不执行,而是返回一个生成器 (内部有__iter__()方法),执行就跟迭代器一样了
    print(type(ret))  查看是什么类型 结果为 generator
    print(dir(ret))  # 查看内部方法
    a=ret.__next__()  # 执行方式:迭代器 点__next__() 可以赋值  遇到这才开始进入函数 自上而下运行 
                不过如果你是一个yield就暂停到这 print(a) print(ret.__next__()) # 此时函数报错,是因为只有一个yiled 可以理解为一个__next__()执行一个yield, __next__() 本来就是一个一个拿 而恰巧遇到yield 暂停函数(分段执行)
    生成器的一个简单作用:  (例子:订衣服)
    
    
    一般函数解决:
    def cloth():
        lst=[]
        for i in range(0,10000):
            lst.append('衣服'+str(i))
        return lst
    
    a=cloth()
    print(a)  # 一次全拿出来 放到列表中
    不完美 目的是我想要几个你给我几个(这样写太占内存,不好)
    所以:
    def cloth1():
        for i in range(0,10000):
            yield  '衣服'+str(i)   #  惰性机制  内部自己执行自加一,不会全部加载出来
    
    g=cloth1()  # 返回一个生成器
    
    print(cloth1().__next__()) # 迭代器 点 __next__() 执行
    
    for i in range(10):  #  取十件
    
        print(g.__next__())  # ⽣成器是⼀个⼀个的指向下⼀个. 不会回去, __next__()到哪, 指针就指到哪⼉.
                              下⼀次继续获取指针指向的值.
    print(g.__next__()) # 从第十个数开始 我又取了一件
    
    for i in g:  #  g他本身也是一个生成器 ,内部含有__iter__() 所以可迭代    内部__next__()不冲突
        print(i)
    
    send 方法  和__next__()一样 都可以让生成器执行到下一个yield
    def func():
    
        print('今天吃的什么饭')
    
        a=yield  '馒头'
        print(a)
        yield '狗粮'
    a=func()
    
    ret=a.__next__()
    print(ret)
    ret1=a.send('胡辣汤')  # 相当于 __next__()
    print(ret1)
    send和__next__()都是让程序向下走一次

    send可以让yield的位置传递参数,不能给最后一个yield发送值 会报错,第一次执行函数是不能用send,就是先用__next__()开下头
    for循环可以直接循环生成器来获取内部元素
    def func():
         print(111)
         yield 222
         print(333)
         yield 444
         print(555)
         yield 666
    gen = func()
    for i in gen:
     print(i)
    结果:
    111
    222
    333
    444
    555
    666
     列表推导式,⽣成器表达式以及其他推导式
    列表推导式是通过一行来构建你想要的列表,常用写法,[结果 for 变量 in可迭代对象]
    lst = [i for i in range(1, 15)]
    print(lst)
    # 还可以进行筛选:
    # 获取1-100所有的偶数
    print([i for i in range(1,101) if i%2==0])
     
    生成器表达式 和 列表表达式一样,只是把[]替换成()
    例子:
    ss=(i for i in range(10))
    print(ss) #generator  直接打印出来就是一个生成器
    我们可以用for循环来循环这个生成器:
    sw=('第%s次打你'% i for i in range(10))
    for i in range(2):
        s=sw.__next__()
        print(s) #  输出0和1 两次 因为取了两个数
    for i in sw:
        print(i) # 全部打印出来,for循环内部有__next__()的东西,还会帮你处理异常(报错)
    生成器表达式也可以进行筛选
    
    
        例子:
    ss=(i*i for i in range(100) if i%3==0)
    
    for i in ss:
        print(i) # 打印出100以内所有能被3整除的数的平方
    
    
    例子: 寻找名字中带有两个e得人的名字
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven',
    'Joe'],
     ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    # 列表推导式写法:
    gen = (name for first in names for name in first if name.count("e") >= 2)
    for name in gen:
     print(name)

    正常代码写法:
    lst=[]
    for name in names:
    for na in name:
    if na.count('e')>=2:
    lst.append(na)
    print(lst)
     

    小结:

    ⽣成器表达式和列表推导式的区别:

    1. 列表推导式比较耗内存. ⼀次性加载. ⽣成器表达式⼏乎不占⽤内存. 使⽤的时候才分
    配和使⽤内存
    2. 得到的值不⼀样. 列表推导式得到的是⼀个列表. ⽣成器表达式获取的是⼀个⽣成器.
    举个栗⼦.
    同样⼀篮⼦鸡蛋. 列表推导式: 直接拿到⼀篮⼦鸡蛋. ⽣成器表达式: 拿到⼀个老⺟鸡. 需要
    鸡蛋就给你下鸡蛋.
    ⽣成器的惰性机制: ⽣成器只有在访问的时候才取值. 说⽩了. 你找他要他才给你值. 不找他
    要. 他是不会执⾏的.
    补充:
    def func():
        print(111)
        yield 222
    g=func() # 生成器
    
    
    g1=(i for i in g)
    # print(g1.__next__())
    
    print(list(g))  # 通过数据转换可以获取生成器相当于print (g.__next__())

    执行顺序 当你取值的时候函数才会被执行, 而且你只有一个__next__()取一次少一个
    总结:

      
    推导式有, 列表推导式, 字典推导式, 集合推导式, 没有元组推导式
    ⽣成器表达式: (结果 for 变量 in 可迭代对象 if 条件筛选)
    ⽣成器表达式可以直接获取到⽣成器对象. ⽣成器对象可以直接进⾏for循环. ⽣成器具有
    惰性机制.
    目前知道了 获取生成器的几种方式:              
             直接生成器点__next__()

    for 循环(目的也是加了__next__())
        通过数据转换可以,不过他会把取得值放到你所转的类型中去
     






  • 相关阅读:
    多重背包 HDU2191
    带限制求最小价值的完全背包 HDU1114
    均分背包 HDU1171
    经典01背包问题 HDU2602
    记忆化搜索 POJ1579
    最大递增子序列变形——二维带权值 O(n*n) HDU1069
    最大递增子序列变形——二维 O(n*logn) TOJ4701
    OCJP(1Z0-851) 模拟题分析(六)over
    OCJP(1Z0-851) 模拟题分析(八)over
    OCJP(1Z0-851) 模拟题分析(九)over
  • 原文地址:https://www.cnblogs.com/systemsystem/p/9919763.html
Copyright © 2011-2022 走看看