生成器和生成器表达式
一. 生成器.
生成器的本质就是迭代器.
在python中有三种方式来获取生成器:
1. 通过生成器函数.
2. 通过各种推导式来实现生成器.
3. 通过数据的转换也可以获取生成器.
特点: 1. 节省内存
2. 惰性机制
3. 只能向前
二. 生成器函数.
这是一个简单的函数
def func(): print("111") return 222 ret = func() print(ret) 结果: 111 222
将函数中的return换成yield就是生成器
def func(): print("111") yield 222 ret = func() print(ret) 结果: <generator object func at 0x10567ff68>
1. gen = func() 函数并不会被执行, 而事故创建一个生成器对象
def func(): print("111") yield 222 gener = func() # 这个时候函数不会执行. 而是获取到生成器 ret = gener.__next__() # 这个时候函数才会执行. yield的作用和return一样. 也是返回数据 print(ret) 结果: 111 222
2. send和__next__()的区别:
1. send和__next__()都是让生成器向下走一次
2. send可以给上一个yield的位置传递值, 不能给最后一个yield发送值, 在第一次执行生成器
代码的时候不能使用send().
def generator(): print(123) content = yield 1 print('=======',content) print(456) yield2 g = generator() ret = g.__next__() print('***',ret) ret = g.send('hello') #send的效果和next一样 print('***',ret) #send 获取下一个值的效果和next基本一致 #只是在获取下一个值的时候,给上一yield的位置传递一个数据 #使用send的注意事项 # 第一次使用生成器的时候 是用next获取下一个值 # 最后一个yield不能接受外部的值
三. 列表推导式, 生成器表达式以及其他推导式.
1. 列表推导式是通过一行来构建你要的列表, 列表推导式看起来代码简单, 但是出现错误之后很难排查.
列表推导式的常用写法:
[结果 for 变量 in 可迭代对象]
例. 从python1期到python14期写入列表lst:
lst = ['python%s' % i for i in range(1,15)] print(lst)
2. 生成器表达式和列表推导式的语法基本是一样的, 只是把[]换成().
3. 生成器表达式和列表推导式的区别:
1. 列表推导式比较耗内存, 一次性记载, 生成器表达式几乎不占用内存, 使用的时候才分配和使用内存.
2. 得到的值不一样, 列表推导式得到的是一个列表, 生成器表达式获取的是一个生成器.
4. 字典推导式: 推导出来的是字典
# 把字典中的key和value互换 dic = {'a': 1, 'b': '2'} new_dic = {dic[key]: key for key in dic} print(new_dic) # 在以下list中. 从lst1中获取的数据和lst2中相对应的位置的数据组成一个新字典 lst1 = ['jay', 'jj', 'sylar'] lst2 = ['周杰伦', '林俊杰', '邱彦涛'] dic = {lst1[i]: lst2[i] for i in range(len(lst1))} print(dic)
5. 集合推导式可以帮我们直接生成一个集合, 集合的特点: 无序, 不重复, 所以集合推导式自带去重功能.
总结: 推导式有列表推导式, 字典推导式, 集合推导式. 没有元组推导式.
生成器表达式: (结果 for 变量 in 可迭代对象 if条件筛选)
生成器表达式可以直接获取到生成器对象, 生成器对象可以直接进行for循环.
最后给大家一个面试题, 难度系数很高.
def add(a, b): return a + b def test(): for r_i in range(4): yield r_i g = test() for n in [2, 10]: g = (add(n, i) for i in g) print(list(g))
提示: 惰性机制, 不到最后不拿值.