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

    生成器

    1. 什么是生成器

    器乃工具也,生成器就是就来生成某种东西的工具

    生成器实际上本质就是迭代器,也是惰性取值,也节省内存

    2. 为什么要有生成器

    既然生成器本质就是迭代器,那么python为什么还要搞一个生成器呢?他俩有啥区别?实际上迭代器是通过可迭

    代对象转换出来的,不是我们想怎么搞就怎么,要取决于可迭代对象,我靠,可迭代对象不是可以自己定义吗?

    这样实际上也自定义了迭代器,不也可以吗?python之父可能觉得不爽,我直接搞一个自定义的迭代器,不通过

    自定义可迭代对象转换这样不好吗?看不惯就造,于是有了生成器

    生成器就是自定义的迭代器,它不依赖可迭代对象,直接造出来,器是工具,工具可以通过函数造出来,所以通过自定义一个特殊的函数,来实现生成器

    3. 生成器怎么用

    3.1 yield关键字

    在函数内部只要有yield关键字,调用函数之后不会执行函数体代码,而是返回一个生成器对象

    def func():
        print('第一次')
        yield 1
        print('第二次')
        yield 2
        print('第三次')
        yield 3
        print('第四次')
    
    
    g = func()	 #  生成器
    print(g)     # <generator object func at 0x000001E30BDDFF10>
    

    3.2 __next__方法

    生成器调用__next__方法也会从里面取出一个值

    def func():
        print('第一次')
        yield 1
        print('第二次')
        yield 2
        print('第三次')
        yield 3
        print('第四次')
    
    
    g = func()
    print(g.__next__())   # 1
    # 生成器调用__next__方法会触发函数体代码的运行,然后遇到yield停下来,将yield后的值当做本次调用的结果返回
    

    yieldreturn关键字都可以返回值,但是return会终止函数 , 但是yield不会 , 而是夯住 , 等待下一次取值

    也就说yield做到了函数体代码中止,是不是很牛逼,以前的函数体代码都是一股烟全执行完毕,现在我们可以通

    过yield关键字,让他先执行一部分,然后主程序去执行其他代码,然后又回来执行函数体剩下的代码,做到了

    从代码的切换从函数内切换到外面然后还能切换回来,我靠,比闭包还cool

    同样生成器当你取完值再取里面就没有值了,再取就报错。

    def func():
        print('第一次')
        yield 1
        print('第二次')
        yield 2
        print('第三次')
        yield 3
        print('第四次')
    
    
    g = func()
    print(g.__next__())   # 1
    print(g.__next__())   # 2
    print(g.__next__())   # 3
    print(g.__next__())   # 报错
    

    3.3 for循环生成器

    生成器自然而然也是可以被for循环的

    def func():
    
        yield 1
    
        yield 2
    
        yield 3
    
    
    g = func()
    
    for i in g:
        print(i)   # 1 2 3
    

    3.4 __iter__方法

    同样生成器调用iter方法也是返回自己本身

    def func():
        print('第一次')
        yield 1
        print('第二次')
        yield 2
        print('第三次')
        yield 3
        print('第四次')
    
    
    g = func()
    print(g)              # <generator object func at 0x00000170511EFF10>
    print(g.__iter__())   # <generator object func at 0x00000170511EFF10>
    

    4. 为yield传值

    yield关键字不但可以返回值,你还可以在函数外部为其传值,不过要通过指定的方法send()

    def dog(name):
        print('%s准备吃东西啦...' % name)
        while True:
            # x拿到的是yield接收到的值
            x = yield 111 # x ='肉包子'
            print('%s吃了%s' % (name, x))
    
    
    g = dog('tom')    # 得到一个生成器赋值给g
    g.send(None)      # 等同于g.__next__(),让函数挂起,就是初始化,当刚得到生成器的时候,光标在开头,初始化光标应该在yield后面
    res = g.send('肉包子')  
    print(res)
    

    然后函数体内部的代码执行到下一次yield右边,挂起,同样会把后面的返回值111返回给这次的调用者即

    g.seng("肉包子")

    注意 :

    刚得到的生成器不能为其yield传非None值,要么你传一个None值,要么你调用g.__next__()
    记住每次send()都是在为yield传值,但是,调用send()的返回值是yield后面的值
    

    5. 小总结

    优点

    • Python使用生成器提供了延迟操作。所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生

      结果。这对于大数据量处理,将会非常有用。

    • 除了延迟计算,生成器还能有效提高代码可读性。

    缺点

    • 只能遍历一次

    生成器迭代器都可以反复创建,迭代器取决于可迭代对象的存在,只要可迭代器对象在,你就可以造迭代器

    取完值,你想还取你就再调用一次__iter__方法,又会返回一个迭代器,当然你取完值,迭代器里面虽然没有

    值了,但是你还以再调用__iter__方法,循环往复。而生成器取完里面的值,你就要在定义一个新的生成器,才

    能继续愉快的取值了,也有人叫这样定义的生成器叫生成器函数

    6. 小练习

    6.1 自定义一个可以无限生成值的生成器

    def nb_g():
        count = 0
        while 1:
            count += 1
            yield count
    

    6.2 自定义一个range()生成器

    def my_range(start,stop,step):
        while start < stop
        	yield start
            strat += step
    
  • 相关阅读:
    昨天晚上简单英文词典查询及排版系统写完了
    c函数 atoi() 将字符串转换为整型 kbhit() 检测是否有按键按下 区分bioskey()
    写了一个字典树
    用scanf清空缓冲区 对比fflush
    爬取千千小说 -- xpath
    第二十六篇 -- 去掉标题栏并自定义标题栏
    git clone 中途停止不动
    使用turtle库画一朵玫瑰花带文字
    正则爬取我要个性网的头像
    用Pygal画一个英雄能力的图
  • 原文地址:https://www.cnblogs.com/xcymn/p/14081671.html
Copyright © 2011-2022 走看看