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]
  • 相关阅读:
    poj 2485 Highways 最小生成树
    hdu 3415 Max Sum of MaxKsubsequence
    poj 3026 Borg Maze
    poj 2823 Sliding Window 单调队列
    poj 1258 AgriNet
    hdu 1045 Fire Net (二分图匹配)
    poj 1789 Truck History MST(最小生成树)
    fafu 1181 割点
    减肥瘦身健康秘方
    人生的问题
  • 原文地址:https://www.cnblogs.com/zouzou-busy/p/13019768.html
Copyright © 2011-2022 走看看