生成器
生成器
一. 生成器的定义:
生成器的本质就是迭代器,在python社区中,大多数时候都把迭代器和生成器是做同一个概念。生成器和迭代器,唯一的不同就是:迭代器都是Python给你提供的已经写好的工具或者通过数据转化得来的,(比如文件句柄,iter([1,2,3])。生成器是需要我们自己用python代码构建的工具。最大的区别也就如此了。
二、生成器的构成
- 生成器表达式
2. 通过生成器函数
3. python内置函数或模块提供
三、生成器函数
def func():
print(11)
return 22
ret = func()
print(ret)
将函数中的return换成yield,这样func就不是函数了,而是一个生成器函数
def func():
print(11)
yield 22
ret = func()
print(ret) 注意:结果 <generator object func at 0x031E5CB0>
执行这个函数的时候,就不再是函数的执行了,而是获取这个生成器对象.
生成器的本质就是迭代器,迭代器如果取值,生成器就如何取值
四、生成器的取值
def func():
print(11)
yield 22
qener = func() # 这个时候函数不会执行,而是获取到生成器(就是那个内存地址!!)
ret = next(qener) # 这个时候函数才会执行
print(ret) # 并且yield会将func生产出来的数据 222 给了 ret
并且生成器函数中可以写多个yield
def func():
print('11')
yield 22
print('33')
yield 44
gener = func()
ret = next(gener)
print(ret)
ret2 = next(gener) # 和迭代器一样,next超过yield的个数就会报错
print(ret2)
五、yield和return的区别
- return一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值,多个值通过元组的形式返回
- yield在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素,多个值通过元组的形式返回
def eat():
for i in range(1,10001):
yield '包子'+str(i)
e = eat()
for i in range(200): # 先吃200个包子
print(next(e)) # 运行一个next就吃一个包子,非常节省内存,而且可以保留上次的位置
六、yieldfrom与yield对比
- python3中提供一种可以直接把可迭代对象中的每一个数据作为生成器的结果进行返回的方法
对比 yield 与 yield from
def func():
lst = ['卫龙', '老冰棍', '北冰洋', '巧克力']
yield lst
g = func()
print(g)
print(next(g)) # 只是返回一个列表
def func1():
lst = ['卫龙', '老冰棍', '北冰洋', '巧克力']
yield from lst
g = func1()
print(g) # 它会将这个可迭代对象(列表)的每个元素当成迭代器的每个结果进行返回
print(next(g))
print(next(g))
print(next(g))
print(next(g))
'''
yield form ['卫龙', '老冰棍', '北冰洋', '巧克力']
等同于:
yield '卫龙'
yield '老冰棍'
yield '北冰洋'
yield '巧克力'
'''
def func():
lst1 = ['卫龙', '老冰棍', '北冰洋', '巧克力']
lst2 = ['馒头', '花卷', '豆包', '大饼']
yield from lst1
yield from lst2
g = func()
for i in g:
print(i)
因为yield from 是将列表中的每一个元素返回,所以如果写两个yield from 并不会产生交替的效果
yield from节省代码,提升效率(代替了for循环)
总结:
- yield from 是将可迭代的每一个元素返回,所以如果写两个yield from 并不会产生交替的效果
- yield from节省代码,提升效率代替了for循环
七、列表推导式与生成器表达式
- 列表推导式:用一行代码构建一个有规律的列表
- 循环模式:[变量(加工后的变量) for 变量 in interable]
- 筛选模式: [变量(加工的变量) for 变量 in iterable if 条件]--就是在循环模式的基础上加上一个判断条件,将满足条件的变量留到列表中
一般写法
lst = []
for i in range(10):
lst.append(i)
print(lst) #[0,1,2,3,4,5,6,7,8,9,]
列表推导式的循环模式
lst = [i for i in range(10)] #循环模式
print(lst) #[0,1,2,3,4,5,6,7,8,9,]
列表推导式的筛选模式
lst = [i for i in range(10) if i % 2==0] #筛选模式
print(lst) #[0,2,4,6,8]
-
生成器表达式
-
生成器表达式和列表推导式在语法上一模一样,只要把[]换成()就可以了
gen = (i**2 for i in range(10)) print(gen) #生成器内存地址
-
如何触发生成器或迭代器
- next
- for循环
- 转换,比如用list()转换成列表
-
生成器的惰性机制
生成器只有在访问时才取值,说白了,你找他要才给你值,不找他要,他是不会执行的
-
-
生成器表达式和列表推导式的区别
- 列表推导式比较消耗内存,所有数据一次加载到内存,而生成器表达式遵从迭代器协议,逐个产生元素
- 得到的值不一样,列表推导式得到的是一个列表,生成器表达式获取的是一个生成器
- 列表推导式一目了然,生成器表达式只是一个内存地址
-
字典推导式
lst1 = ['jay', 'jj', 'meet'] lst2 = ['周杰伦', '林俊杰', 'haven'] dic = {lst1[i]:lst2[i] for i in range(len(lst1))} print(dic) # {'jay': '周杰伦', 'jj': '林俊杰', 'meet': 'haven'}
-
集合推导式
lst = [1, 2, 3, -1, -3, -7, 9] s={i for i in lst} print(s) #{1, 2, 3, 9, -7, -3, -1}
八、匿名函数与内置函数
-
匿名函数:没有名字的函数,lambda
- 只能构建简单的函数,一句话函数
def func(x,y): return x+y print(func(x,y)) func2 = lambda x,y:x+y #lambda 定义一个匿名函数 print(func2(1,2)) func4 = lambda a,b:a if a>b else b #匿名函数最常用的就是与内置函数的结合使用
-
内置函数:python中的内置函数有68种
-
eval():剥去字符串的外衣,返回最终结果,慎用
s = '5+9' print(eval(s)) #14
-
exec():执行字符串中的代码流,没有返回值
s = """ for i in [1,2,3]: print(i) """ exec()
-
hash()获取一个对象(可哈希对象:int,str,bool,tuple,)的哈希值
-
help():查看函数或模块的详细说明
-
callable():用于查看一个对象是否可以被调用的,如果返回True,仍有可能调用失败,但是返回False,则一定不会成功
name = 'haven' def func(): pass print(callable(name)) #False print(callable(func)) #True
-
int():用于将一个字符串或数字转换为整型
print(int()) # 0 print(int('12')) # 12 print(int(3.6)) # 3
-
float():用于将整数和字符串转换成浮点数
-
complex():用于创建复数,或者将字符串或数换成复数
-
bin():将十进制换成二进制
-
oct():将十进制转换成八进制字符串返回
-
hex():将十进制转换成十六进制字符串并返回
-
divmod():j计算除数与被除数的结果,返回一个包含商和余数的元组(a//b,a%b)
print(divmod(10,3)) #(3,1) 分页用到
-
round():保留浮点数的小数位数,默认保留整数
print(round(3.1415926,2)) #3.14 四舍五入
-
pow():求x**y次幂
# 第三个参数为x**y的结果对z取余 print(pow(2, 3)) # 2**3 8 print(pow(2, 3, 3)) # 8对3取余 2
-
ord():输入字符找该字符编码的位置,unicode
-
chr():输入位置数字找出其对应的字符,unicode,有用
-
repr():返回一个对象的string形式(原形毕露)
print(repr('123')) # '123
-
all():可迭代对象中全是True才是True
-
any():可迭代对象中,有一个True就是True
-
接下来的都很重要!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
print():屏幕输出
print(1,2,3,sep = '_') #1_2_3 sep设定分隔符,默认空格 print(1,2,end=' ') # end默认是\n
-
list():定义或转换列表
lst = list('asdf') #括号内可放迭代对象 # ['a','s','d','f']
-
dic():字典
字典的创建方式
dic = {1:'2'} dic = {i:1 for i in range(3)} dic = dict(one=1,two=2,three=3) dic = dict.fromkeys(key,valus)
-
abs():获取绝对值
print(abs(-10)) #10
-
sum():求和
sum(iterable,初始默认值为0) print(sum([1, 2, 3, 4])) # 10 print(sum([1, 2, 3, 4], 10)) # 20
-
max():求最大值 用法与min()完全相同
-
min():求最小值
print(min([22,3,43,45,3])) # 2 lst = [('maqian', 20), ('xihong', 18), ('xiaomi', 22)] 找年龄最小的元组 print(min(lst)) #('maqian', 20),按照可迭代对象的第一个元素的第一个字符排序 通过设置key去使用min,key=函数名,返回值是什么就按照什么比较 min()会自动将可迭代对象的每一个元素作为实参传给函数,最后将遍历的那个元素返回 print(min(lst,key=lambda x:lst[1])) #使用匿名函数
-
reversed():将一个可迭代对象反转,返回反转的迭代器
s = 'maqian' for i in reversed(s): print(i) # n a i q a m
-
bytes():编码
s = 'haven' print(s.encode('utf-8')) #第一种方法 print(bytes(s,encoding='utf-8')) #第二种方法
编码 b = b'\xe5\xb0\x8f\xe6\x98\x8e' print(b.decode('utf-8')) # 第一种方法 print(str(b, encoding='utf-8')) # 第二种方法
-
内置函数的补充
-
zip():拉链方法,用于将可迭代对象作为参数,将对象中对应的元素打包成一个元组,然后返回这些由这些元组组成的内容(迭代器),如果这个可迭代对象的元素个数不一致,则按照长度最短的返回
lst1 = [1,2,3] lst2 = ['a','b','c','d'] lst3 = (11,12,13,14,15) for i in zip(lst1,lst2,lst3): print(i) 结果: (1, 'a', 11) (2, 'b', 12) (3, 'c', 13)
-
sorted():排序
l1 = [7, 4, 1, 6,] print(sorted(l1)) # 形成了新的列表 # 加key lst = [ {'name': 'xiaohong', 'age': 73}, {'name': 'xiaoming', 'age': 35}, {'name': 'xiaoli', 'age': 25}, ] print(sorted(lst,key=lambda x:x['age'])) #按照年龄排序 print(sorted(lst,key=lambda x:x['age'],reverse=True)) #第三个参数,逆序
-
filter():过滤,相当于生成器表达式的筛选模式,返回一个迭代器
l1 = [56, 67, 12, 34, 78, 90] print(i for i in l1 if i > 60) #[67,78,90] print(list(filter(lambda x:x>60,l1))) #[67,78,90]
-
map():相当于生成器表达式的循环模式
l1 = [56, 67, 12, 34, 78, 90] print(i**2 for i in l1) #<generator object <genexpr> at 0x000001E97FFFC888> print(list(map(lambda x:x**2,l1))) #[3136, 4489, 144, 1156, 6084, 8100]
-
reduce(): python3从内置函数剔除了,放到了模块中
就是把列表,元组的成员按照既定的规则累加
from functools import reduce print(reduce(lambda x,y:x+y,[1,2,3,4,5])) #15 """ 第一次: x,y 1,2 求和 3 记录到内存 第二次: x,y 3,3 求和 6 记录到内齿 第三次: x,y 6,4 求和 10 记录到内齿 第四次: x,y 10,5 求和 15 返回 """