zoukankan      html  css  js  c++  java
  • 生成器和生成器表达式

    一.生成器
    1.生成器
    • 生成器的本质就是迭代器
    • 生成器的特点和迭代器一样, 取值方式和迭代器一样
    • 生成器一般由生成器函数或者生成器表达式来创建
    • 生成器说白了就是手写的迭代器
     
    2.生成器函数
    • 和普通函数没有区别, 里面有yield的函数就是生成器函数.
    • 生成器函数在执行的时候, 默认不会执行函数体, 返回的是生成器.
    • 通过生成器的__next__()分段执行这个函数.
    • send()和__next__()功能一样, 唯一的区别是send()可以给上一个yield的位置传值.
    • send()不能在开头,最后一个yield也不可以用send()
     
    # 生成器函数
    def func():
        print("娃哈哈")
        yield 111        # 函数中有yield 这就是生成器函数
     
    ret = func()         # 生成器, 这里不会执行函数的, 拿到的结果是生成器
    print(ret)             # 结果: <generator object func at 0x000001AB93D4FE60>
     
    def func():
        print("这是第一个")
        yield 111
        print("这是第二个")
        yield 222
        print("这是最后一个")
        yield 333
     
    ret = func()
    print(ret.__next__())    # 执行函数, 执行到下一个yield,
    print(ret.__next__())    # 继续执行到下一个yield
    print(ret.__next__())    # 继续执行到下一个yield
    print(ret.__next__())    # 报错, 错误信息StopIteration
     
    send()和__next__()
    效果一样, 只是send()可以给上一个yield的位置传值.
    send()不能在开头
     
    def func():
        print("这是第一个")
        a = yield 111
        print(a)
        print("这是第二个")
        b = yield 222
        print(b)
        print("这是第三个")
        c = yield 333
        print(c)
        print("这是最后一个")
        yield 444
     
    g = func()
    print(g.__next__())                    # 第一个写next, 而不是send, 通过send的定义, 也能了解到, send()只是给上一个yield的位置传值, 这里还没有上一个
    print(g.send("韭菜盒子"))         # send()里面必须写值, 不然报错
    print(g.send("锅包肉"))
    print(g.send("煎饼果子"))
     
    结果:
    这是第一个
    111
    韭菜盒子
    这是第二个
    222
    锅包肉
    这是第三个
    333
    煎饼果子
    这是最后一个
    444
     
    如果不使用send()传值, 我们看一下结果
    def func():
        print("这是第一个")
        a = yield 111
        print(a)
        print("这是第二个")
        b = yield 222
        print(b)
        print("这是第三个")
        c = yield 333
        print(c)
        print("这是最后一个")
        yield 444
     
    g = func()
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
     
    结果:
    这是第一个
    111
    None                # a 取不到值
    这是第二个
    222
    None
    这是第三个
    333
    None
    这是最后一个
    444
     
    图解: a = yield 111 程序执行到这里时, 遇见"什么=什么", 那一定先执行等号右边的, 等号右边的是yield, 
    我们说过生成器函数在执行时,遇到yield就返回, 遇到yield就返回, 那执行完等号右边的,本次执行结果, 函数返回结果, 那a=就取不到值, 结果就为None.
    使用send()可以在结束时, 给上一个yield的位置传一个值, 正好是a=yield的位置, 所以a就有值了.
     
    获取内部的元素
    def func():
    yield 11
    yield 22
    yield 33
    yield 44
    yield 55
     
    # for循环
    for i in func():        # 使用内部的__next__()来实现
        print(i)
     
    # list
    print(list(func()))      # 使用内部的__next__()来实现
     
     
    二.推导式
    1.推导式
    用一句话来生成一个列表.
    基本语法:
        [结果 for循环]
    其他:
    [结果 for循环 条件]
     
    2.列表推导式
     
    # 分别使用算法和推导式, 生成一个列表
    # 算法
    lst = []
    for i in range(1,10):
        lst.append(i)
        print(lst)
     
    # 列表推导式
    lst = [i for i in range(1,10)]
    print(lst)
     
    # 加个判断
    lst = [i for i in range(100) if i % 2 == 1]
    print(lst)
     
    注: 等式太复杂,或者太长的话, 都不推荐使用,排错不好排
     
    3.字典推导式
    用法:{k:v for循环 条件}
     
    # 用列表里的值和索引组成一个列表
    lst = [11, 22, 33, 44]
    dic = {i: lst[i] for i in range(len(lst))}
    print(dic)
     
    # 结果:
    {0: 11, 1: 22, 2: 33, 3: 44}
     
    4.集合推导式
    用法:{k for循环 条件}
     
    # 生成一个集合
    lst = [1, 1, 2, 2, 3, 3]
    se = {el for el in lst}
    print(se)
     
    # 结果:
    {1, 2, 3}        # 注意集合的特性,去重,所以这里,就三个值
     
    注:
    没有元组推导式, 这和元组的特性有关, 只能看, 不能增删改, 你想想就这个增,一个一个往里面添加, 是不是, 那肯定做不到了.
     
    三.生成器表达式
    语法格式:(和推导式的几乎一行, 只是把[]换成())
    (结果 for循环 条件)
     
    1.获取生成器表达式的元素
    # __next__()
    ge = (i for i in range(1, 5))
    print(ge)                        # 结果: <generator object <genexpr> at 0x000001DE2D73FDB0>
     
    print(ge.__next__())        # 取值: 1
    print(ge.__next__())        # 2
    print(ge.__next__())        # 3
    print(ge.__next__())        # 4
    print(ge.__next__())        # 报错,StopIteration
     
    # for循环, 可迭代
    ge = (i for i in range(1, 5))
    for i in ge:
        print(i)
     
    # list
    ge = (i for i in range(1, 5))
    print(list(ge))
     
    # 结果:
    [1, 2, 3, 4]
     
    2.生成器表达式和列表推导式的区别
    • 列表推导式比较耗内存, 一次性加载.; 生成器表达式几乎不占用内存, 使用的时候才分配和使用内存.
    • 得到的值不一样.列表推导式得到的是一个列表;生成器表达式获取的是一个生成器.
     
    lst = [i for i in range(1, 5)]
    print(lst)            # 结果: [1, 2, 3, 4]
     
    ge = (i for i in range(1, 5))
    print(ge)           # 结果: <generator object <genexpr> at 0x0000020B074BFDB0>
     
     
    生成器的惰性机制: 生成器只有在访问的时候才取值, 说白了, 你找他要, 他才给你值, 不找他要, 他是不会执行的.
    想想鸡蛋和老母鸡, 列表推导式是给你一筐鸡蛋, 生成器表达式是给你一只鸡,要的时候给你下个蛋, 要的时候给你下个蛋, 就是这样.
  • 相关阅读:
    (转)Hibernate 注解详解
    PHP - jsPDF+html2canvas实现网页截图导出PDF
    (转)PHP-Sublime Text3插件&快捷键(MAC)
    POI
    maven中使用jstl
    树莓派使用pptpd搭建PPTP服务器
    树莓派网络对时
    Debian 安装 oracle java
    让树莓派(RaspberryPi)显示中文
    树莓派搭建minecraft服务器
  • 原文地址:https://www.cnblogs.com/facelessmen/p/9471490.html
Copyright © 2011-2022 走看看