迭代器,生成器函数和各种推导式
一.迭代器
- 一个数据类型中包含了__iter__函数表示这个数据是可迭代的
- 特征:
1. 省内存
2. 惰性机制
3. 只能向前. 不能后退
- 作用:统一了各种数据类型的遍历
- dir(数据类型):
dir() 可以帮我们查看xxx数据能够执行的操作
例如
print(dir(str)) # 有__iter__,是可迭代对象 print(dir(int)) # 没有__iter__,不是可迭代对象 print(dir(list)) # 有__iter__,是可迭代对象 print(dir(dict)) # 有__iter__,是可迭代对象 print(dir(bool)) # 没有__iter__,不是可迭代对象
# 共性:所有带有__iter__的东西都可以进行for循环, 带有__iter__的东西就是可迭代对象
- 判断迭代器和可迭代对象的方案(野路子)
__iter__ 可迭代的
__iter__ __next__ 迭代器
- 判断迭代器和可迭代对象的方案(官方)
from collections import Iterable, Iterator
isinstance(对象, Iterable) 是否是可迭代的
isinstance(对象, Iterator) 是否是迭代器
#借助于两个模块 Iterator迭代器, Iterable可迭代的 from collections import Iterable, Iterator lst = [1,2,3] print(lst.__next__()) print(isinstance(lst, Iterable)) # xxx是否是xxx类型的. True print(isinstance(lst, Iterator)) # xxx是否是xxx迭代器. False it = lst.__iter__() # 迭代器一定可迭代, 可迭代的东西不一定是迭代器 print(isinstance(it, Iterable)) # xxx是否是xxx类型的. True print(isinstance(it, Iterator)) # xxx是否是xxx迭代器. True
- 迭代器一定可迭代, 可迭代的东西不一定是迭代器
- 模拟for循环
# 模拟for循环 for el in lst:
lst=[1,2,3] it = lst.__iter__() # 获取到迭代器 while 1: # 循环 try: # 尝试 el = it.__next__() # 那数据 print(el) except StopIteration: # 出了错误, 意味着数据拿完了 break # 结束循环
二.生成器定义与获取
- 定义:生成器实质就是迭代器.
- 在python中有三种方式来获取生成器:
- 通过生成器函数
- 通过各种推导式来实现生成器
- 通过数据的转换也可以获取生成器
def func(): print("我叫周润发") yield "林志玲" # yield表示返回. 不会终止函数的执行 ret = func() # 执行函数, 此时没有运行函数. 此时我们拿到的是生成器 print("返回值是", ret) # <generator生成器 object func at 0x0000000009E573B8> # 执行到下一个yield print(ret.__next__()) # 第一次执行__next__此时函数才开始执行 print(ret.__next__()) # 执行到下一个yield print(ret.__next__()) # StopIteration
- 我们可以看到, yield和return的效果是一样的. 有什么区别呢?
yield是分段来执行一个函数. return是直接停止执行函数.
- 生成器函数在执行的时候返回生成器. 而不是直接执行此函数
-
能向下执行的两个条件:
__next__(), 执行到下一个yield
send(), 执行到下一个yield, 给上一个yield位置传值
def func():
print("韭菜盒子")
a = yield "韭菜鸡蛋"
print("a", a)
b = yield "韭菜西红柿"
print("b", b)
c = yield "火烧"
print("c", c)
gen = func()#获取生成器
print(gen.__next__()) # 执行到第一个yield
print(gen.send("篮球")) # 给上一个yield位置传值,即给a一个值'篮球'
print(gen.send("足球")) # 给上一个yield位置传值,即给b一个值'足球'
- 所有的生成器都是迭代器都可以直接使用for循环
- 都可以使用list()函数来获取到生成器内所有的数据
-
生成器中记录的是代码而不是函数的运行
def func(): print("值 1") yield "值2"
gen= func()#获取生成器
- gen = func() # 创建生成器. 此时运行会把生成器函数中的代码记录在内存
- 当执行到__next__(), 运行此空间中的代码, 运行到yield结束.
- 优点: 节省内存, 生成器本身就是代码. 几乎不占用内存
- 特点: 惰性机制, 只能向前. 不能反复
三.生成器表达式
(结果 for循环 if...)
g =(i for i in range(10)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(iter(g))
四.各种推导式
- 列表推导式 [结果 for循环 if...]
lst = [i for i in range(1, 19)] print(lst)
- 字典推导式 {结果(k:v) for循环 if...}
- 集合推导式 {结果(k) for循环 if...}
元组没有推导式,小括号括起来的是生成器表达式
补充:yield from
def func():
lst = ["衣服%s" % i for i in range(500)] yield from lst # 可以把一个可迭代对象分别进行yield返回
lst1 = ["python%s" % i for i in range(18)] yield from lst1 gen = func() print(gen.__next__()) print(gen.__next__())
lst全部返回完后才会返回lst1,不会交叉返回
lst = ["衣服%s" % i for i in range(500)] yield from lst 这个就相当于 for i in range(500): yield "衣服%s" % i