python--迭代器、isinstance、生成器、send

简介: 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]

相关文章
|
14天前
|
大数据 数据处理 开发者
Python中的迭代器和生成器:不仅仅是语法糖####
本文探讨了Python中迭代器和生成器的深层价值,它们不仅简化代码、提升性能,还促进了函数式编程风格。通过具体示例,揭示了这些工具在处理大数据、惰性求值及资源管理等方面的优势。 ####
|
2月前
|
存储 索引 Python
|
21天前
|
JavaScript 前端开发 算法
python中的列表生成式和生成器
欢迎来到瑞雨溪的博客,这里是一位热爱JavaScript和Vue的大一学生的天地。通过自学前端技术2年半,现正向全栈开发迈进。如果你从我的文章中受益,欢迎关注,我将持续更新高质量内容,你的支持是我前进的动力!🎉🎉🎉
21 0
|
2月前
|
Python
Python生成器、装饰器、异常
【10月更文挑战第15天】
|
2月前
|
传感器 大数据 数据处理
深入理解Python中的生成器:用法及应用场景
【10月更文挑战第7天】深入理解Python中的生成器:用法及应用场景
56 1
|
2月前
|
存储 数据处理 Python
深入解析Python中的生成器:效率与性能的双重提升
生成器不仅是Python中的一个高级特性,它们是构建高效、内存友好型应用程序的基石。本文将深入探讨生成器的内部机制,揭示它们如何通过惰性计算和迭代器协议提高数据处理的效率。
|
1月前
|
存储 程序员 数据处理
深入理解Python中的生成器与迭代器###
本文将探讨Python中生成器与迭代器的核心概念,通过对比分析二者的异同,结合具体代码示例,揭示它们在提高程序效率、优化内存使用方面的独特优势。生成器作为迭代器的一种特殊形式,其惰性求值的特性使其在处理大数据流时表现尤为出色。掌握生成器与迭代器的灵活运用,对于提升Python编程技能及解决复杂问题具有重要意义。 ###
|
2月前
|
存储 索引 Python
Python 迭代器是怎么实现的?
Python 迭代器是怎么实现的?
32 6
|
3月前
|
索引 Python
解密 Python 迭代器的实现原理
解密 Python 迭代器的实现原理
49 13
|
2月前
|
存储 大数据 数据处理
Python 中的列表推导式与生成器:特性、用途与区别
Python 中的列表推导式与生成器:特性、用途与区别
28 2