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

    1、Python 中提供的 生成器:

      本质我们自己写的能实现迭代器功能的东西,就叫生成器。

      1.1生成器函数:

      常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果。在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行

      1.2.生成器表达式:

      类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

    2、生成器Generator:

      本质:迭代器 ( 所以自带了 __iter__方法和 __next__方法,不需要我们去实现)

      特点:惰性运算,开发者自定义

    3、生成器函数:

      划重点:

        ① 必须含有yield关键字

          ② 执行之后会得到一个生成器对象,作为返回值

    def generator():
        print('123')
        yield 'ab'
    ret = generator()
    print(ret)           # <generator object generator at 0x000001DA911EC3B8>
    print(ret.__next__())     # 第一次执行函数体内的代码,如上①输出123 ②return ab
    def wahaha():
        for i in range(2000):
            yield '娃哈哈%s'%i
    g = wahaha()
    count = 0
    for i in g:        # 循环迭代输出
        count += 1
        print(i)
        if count > 100:
            break
    print('*********',g.__next__())   #********* 娃哈哈101

    4、field关键字

      4.1 yield和return的区别

    # 在一个函数里return只能执行一次,return之后函数就彻底结束了:
        def test_return():
            return 1
        return 2  # 永不执行
        return 3  # 永不执行
    
        def test_return2():
            for i in range(10):
                return i  # 只能返回0,函数就结束了
    
    ——————————————————————————————————————
    
    # yield之后可以保存函数的运行状态,下次继续执行:
    在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行
    def test_yield(): yield 1 yield 2 # 下次next()后执行 yield 3 # 下次next()后执行 def test_yield2(): for i in range(10): yield i # 每调用一次next()就会依次弹出0~9

      4.2 yield的作用

    # ① yield把函数变成了生成器(生成器就是迭代器)。
    # ② 为函数封装好了__iter__和__next__方法,把函数的执行结果做成了迭代器。
    # ③ 遵循迭代器的取值方式 — obj.__next__(),触发的是函数的执行。函数暂停与继续执行的状态都是由yield保存的。
    # 倒计时的例子
    
    def countdown(n):
        print("倒计时开始")
        while n > 0:
            yield n
            n -= 1
        print("发射")
    
    g = countdown(5)
    print(g.__next__())  # 打印"倒计时开始" 返回5 (此时n=5)
    print(g.__next__())  # 返回4 (此时n=4)
    print(g.__next__())  # 返回3 (此时n=3)
    print(g.__next__())  # 返回2 (此时n=2)
    print(g.__next__())  # 返回1 (此时n=1)
    print(g.__next__())  # 打印"发射" 抛出StopIteration异常(此时n=0)

      4.3 yield from:在一个生成器中引用另外一个生成器

      yield from后面需要加的是可迭代对象,它可以是普通的可迭代对象,也可以是迭代器,甚至是生成器。

      详细查看  https://www.cnblogs.com/wongbingming/p/9085268.html

    def generator():
        a = '12312312'
        b = 'asdhughiwu'
        yield from a
        yield from b
    g = generator()
    for i in g:
        print(i)
    
    # 运行结果:
    1
    2
    3
    1
    2
    3
    1
    2
    a
    s
    d
    h
    u
    g
    h
    i
    w
    u
    yield from
    astr='ABC'       # 字符串
    alist=[1,2,3]    # 列表
    adict={"name":"wangbm","age":18}   # 字典
    agen=(i for i in range(4,8))    # 生成器
    
    def gen(*args, **kwargs):
        for item in args:
            yield item    # 此处返回的是'ABC',[1,2,3],{"name":"wangbm","age":18},<generator object <genexpr> at 0x000001D0A010C3B8>
            yield from item    # 相当于 for i in item:yield i
    
    new_list=gen(astr, alist, adict, agen)
    print(list(new_list))
    
    
    # 运行结果:
    # ['ABC', 'A', 'B', 'C', [1, 2, 3], 1, 2, 3, {'name': 'wangbm', 'age': 18}, 'name', 'age', <generator object <genexpr> at 0x00000256B8D6C3B8>, 4, 5, 6, 7]

    5、send关键字

      yield可以返回值,也可以接收值。

      通过生成器的send方法可以给yield传值。

    # 必须先执行__next__,才能执行send()
    # send两个作用:
        # 1.给yield传值  
        # 2.继续执行函数
    
    def eat(name):
        print('%s要开始吃了!' % name)
        while 1:
            food = yield
            print('{0}在吃{1}'.format(name, food))
    
    a = eat('alex')
    a.__next__()  # 初始化,让函数暂停在yield处
    a.send('包子')  
    a.send('饺子')

    6、生成器表达式

      详见:https://www.cnblogs.com/timetellu/p/10677743.html

      把列表解析的[ ]换成( )得到的就是生成器表达式:

    sum(x ** 2 for x in range(4))
    
    # 不用多此一举构造一个列表
    # sum([x ** 2 for x in range(4)]) 

    7、生成器相关面试题

    # 只能取一次值
    
    def demo():
        for i in range(10):
            yield i
    g = demo()
    
    g1 = (i for i in g)
    g2 = (i for i in g1)
    print(list(g1))      # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    print(list(g2))      # [ ]
    面试题1
    def add(n,i):
        return n+i
    def test():
        for i in range(4):   # [0,1,2,3]
            yield i
            
    g = test()
    for n in [1,10]:
        g = (add(n,i) for i in g)
        
    print(list(g))    #到list(g)才执行,向上寻找g,取得是for循环最后一步的执行结果:
                            # 执行g = (add(n,i) for i in (add(n,i) for i in test()))  (此时n=10)
    
    运行结果:
    [20, 21, 22, 23]
    
    ### for循环套生成器表达式的,执行过程拆开
    # n = 1时,
    # g0 = (add(n,i) for i in g)   
    # n = 10时,
    # g1 = (add(n,i) for i in g0)   
    
    # g = (add(n,i) for i in (add(n,i) for i in test()))   此时n = 10
    # g = (add(10,i) for i in (10,11,12,13))
    面试题2
  • 相关阅读:
    关键字与标识符
    JAVA 程序的基本语法
    第一个java程序中文乱码以及如何解决
    第一个java程序以及java的运行机制
    java中求余%与取模floorMod的区别
    Volley 框架解析(二)--RequestQueue核心解读
    Volley 源码解析
    Android之Activity系列总结(三)--Activity的四种启动模式
    Android之Activity系列总结(二)--任务和返回栈
    Android之Activity系列总结(一)--Activity概览
  • 原文地址:https://www.cnblogs.com/timetellu/p/10681281.html
Copyright © 2011-2022 走看看