zoukankan      html  css  js  c++  java
  • python--迭代器、isinstance、生成器、send

    迭代器

     isinstance(对象, 类型) 判断xx对象是否是xxx类型的

    from collections import Iterable  # 可迭代的
    from collections import Iterator  # 迭代器

    判断列表 [1,2,3] 是不是可迭代的

    lst = [1, 2, 3]
    print(isinstance(lst, list))

    结果

    True # 可迭代的
    • 可迭代对象(Iterable):内部包含__iter__().
    • 迭代器(Iterator): 内部含有__iter__() __next__()
    • dir()来查看一个对象,数据类型中包含了哪些东西
    • 迭代器里面一定有__next__(), __iter__()
    • 判断是否是可迭代的 迭代器一定是可迭代的

    str, list, tuple, set, dictf, range都是可迭代的,int不是可迭代的,如果执行for i in 123:会报错'int' object is not iterable

    迭代器的特点:

    • 省内存
    • 惰性机制(__next__一个出来一个)
    • 只能往后拿,不能往前拿
    lst = [1, 2, 3]
    s = "王尼玛"
    print("__iter__" in dir(s))  # 可迭代的
    print("__iter__" in dir(lst))  # 可迭代的
    print("__iter__" in dir(123))  # 不可迭代的

    结果:

    True
    True
    False

    list是一个Iterable.可迭代的

    lst = ["皇阿玛", "皇额娘", "容嬷嬷", "紫薇"]
    # 获取迭代器
    it = lst.__iter__()
    # 迭代器往外拿元素. __next__()
    print(it.__next__())  # 皇阿玛
    print(it.__next__())  # 皇额娘
    print(it.__next__())  # 容嬷嬷
    print(it.__next__())  # 紫薇
    print(it.__next__())  # 迭代到最后一个元素之后. 再进行迭代就报错了  StopIteration

    结果:

    皇阿玛
    皇额娘
    容嬷嬷
    紫薇
    # 还有个报错
    lst = [1, 2, 3]
    from collections import Iterable  # 可迭代的
    from collections import Iterator  # 迭代器
    
    print(isinstance(lst, Iterable))
    print(isinstance(lst, Iterator))
    print(isinstance(lst, list))

    结果:

    True
    False
    True

    生成器

    生成器的本质就是迭代器

    生成器的三种创建办法:

    • 通过生成器函数
    • 通过生成器表达式创建生成器
    • 通过数据转换

    生成器函数:

    • 函数中包含了yield的就是生成器函数
    • 注意:生成器函数被执行. 获取到的是生成器. 而不是函数的执行

    生成器表达式:

    • (结果 for 变量 in 可迭代对象 if 筛选)

    取值:

    •  __next__()
    • send(值) 给上一个yield位置传一个值, 第一个和最后一个yield不用传值
    • 可以for循环
    • list(g)

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

    所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

    import time
    
    
    def func():
        sum = 0
        print('in the func...')
        while 1:
            yield sum
    
    
    f = func()  # 并不会执行func函数
    print('abc')
    time.sleep(20)
    print(f.__next__())

    结果:

    abc
    in the func...
    0

    只有遇到__next__时才会执行函数,这是生成器的惰性机制造成的。

    def func():
        print("我是周杰伦")
        yield "昆凌"  # 函数中包含了yield, 当前这个函数就不再是普通的函数了. 是生成器函数
        print("我是王力宏")
        yield "李云迪???"
        print("我是笛卡尔积")
        yield "笛卡尔积是谁"
        print("你好啊")  # 最后一个yield之后如果再进行__next__()会报错
    
    
    g = func()  # 通过函数func()来创建一个生成器,生成器的本质是迭代器. 迭代器可以被迭代 生成器可以直接for循环
    print(g)
    print(g.__next__())
    print(g.__next__())

    结果:

    <generator object func at 0x02D26870>
    我是周杰伦
    昆凌
    我是王力宏
    李云迪???

    return 直接返回结果. 结束函数的调用

    yield 返回结果.可以让函数分段执行

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

    print((i*2 for i in range(10)))

    结果:

    <generator object <genexpr> at 0x03378F30>

    只是返回了生成器的内存对象,没有调用,就没有生成

    a = (i * 2 for i in range(4))
    for i in a:
        print(i)

    结果:

    0
    2
    4
    6
    a = (i * 2 for i in range(4))
    print(a.__next__())
    print(a.__next__())
    print(a.__next__())

    结果:

    0
    2
    4

    只记录当前的位置,只有一个__next__()方法

    生成者和消费者

    import time
    
    
    def consumer(name):
        print("%s 准备吃包子啦!" % name)
        while True:
            baozi = yield  # 停止,下面的代码先不执行
    
            print("包子[%s]来了,被[%s]吃了!" % (baozi, name))
    
    
    def producer(name):
        c = consumer('A')
        c2 = consumer('B')
        c.__next__()
        c2.__next__()
        print("老子开始准备做包子啦!")
        for i in range(5):
            time.sleep(1)
            print("做了2个包子!")
            c.send(i)  # 跳到yield,执行下面的代码
            c2.send(i)
    
    
    producer("zou")

    结果:

    A 准备吃包子啦!
    B 准备吃包子啦!
    老子开始准备做包子啦!
    做了2个包子!
    包子[0]来了,被[A]吃了!
    包子[0]来了,被[B]吃了!
    做了2个包子!
    包子[1]来了,被[A]吃了!
    包子[1]来了,被[B]吃了!
    做了2个包子!
    包子[2]来了,被[A]吃了!
    包子[2]来了,被[B]吃了!
    做了2个包子!
    包子[3]来了,被[A]吃了!
    包子[3]来了,被[B]吃了!
    做了2个包子!
    包子[4]来了,被[A]吃了!
    包子[4]来了,被[B]吃了!

    send

    next__() 可以让生成器向下执行一次

    send() 也可以让生成器向下执行一次, 给上一个yield传一个值, 第一个不能用send(). 最后一个也不要传值

    def func():
        print("大碴粥")
        a = yield "11"
        print(a)
        print("狗不理")
        b = yield "22"
        print(b)
        print("大麻花")
        yield "33"
    
    
    g = func()
    print(g.__next__())
    print(g.send(1))
    print(g.send(2))

    结果:

    大碴粥
    11
    1
    狗不理
    22
    2
    大麻花
    33

    代码分析:

    执行print(g.__next__()),执行到yield "11"结束,左边的a=yield "11"没有执行,因为赋值运算先执行右边的,而生成器遇到yield就停止。这句print(g.send(1))执行a=yield "11"左边的,也就是把send里面的值1赋值给了a,然后到 yield "22"结束

    def eat():
        print("我吃什么啊")
        a = yield "馒头"
        print("a=", a)
        b = yield "大饼"
        print("b=", b)
        c = yield "韭菜盒子"
        print("c=", c)
        yield "GAME OVER"
    
    
    gen = eat()  # 获取⽣成器
    ret1 = gen.__next__()
    print(ret1)
    ret2 = gen.send("胡辣汤")
    print(ret2)
    ret3 = gen.send("狗粮")
    print(ret3)
    ret4 = gen.send("猫粮")
    print(ret4)

    结果:

    我吃什么啊
    馒头
    a= 胡辣汤
    大饼
    b= 狗粮
    韭菜盒子
    c= 猫粮
    GAME OVER
    def func():
        yield 11
        yield 22
        yield 33
        yield 44
    
    
    g = func()
    lst = list(g)  # 可迭代对象
    print(lst)

    结果:

    [11, 22, 33, 44]
  • 相关阅读:
    MongoDB存储时间
    如何在博客园随笔中增加章节导航
    如何优雅地从CSDN转载文章
    线段树详解(原理、实现与应用)
    Codeforces 1076D——最短路算法
    顶点支配、独立与覆盖
    CodeForces
    数据结构一——顺序表
    平面图的基本概念及性质
    编程之美——一摞烙饼的排序(暴搜+剪枝)
  • 原文地址:https://www.cnblogs.com/zouzou-busy/p/13019768.html
Copyright © 2011-2022 走看看