生成器
生成器函数:函数体内包含有yield关键字,该函数执行的结果是生成器,生成器在本质上就是迭代器。
def foo(): print('first------>') yield 1 print('second----->') yield 2 print('third----->') yield 3 print('fouth----->') g=foo() from collections import Iterator print(isinstance(g,Iterator)) print(g)
yield的功能:
1.与return类似,都可以返回值,但不一样的地方在于可以有多个yield,每个yield能够返回一次值,而return只能返回一次值就结束了
2.为函数封装好了__iter__和__next__方法,把函数的执行结果做成了迭代器
3.遵循迭代器的取值方式obj.__next__(),触发的函数的执行,函数暂停与再继续的状态都是由yield保存的
生成器的使用
def foo(): print('first------>') yield 1 print('second----->') yield 2 print('third----->') yield 3 print('fouth----->') g=foo() print(g.__next__()) print(g.__next__()) print(g.__next__()) # print(g.__next__()) 输出结果 first------> 1 second-----> 2 third-----> 3
第一次g.__next__()在函数体的第一个yield结束后暂停,并执行前面的指令
第二次g.__next__()在函数体的第二个yield结束后暂停,并执行前面的指令
第三次g.__next__()在函数体的第三个yield结束后暂停,并执行前面的指令
如果来第四次g.__next__()方法,将抛出StopIteration提示错误
for循环调用:for会自动处理StopIteration,当遇到StopIteration自动停止
for i in g: #obj=g.__iter__() #obj.__next__() print(i)
输出结果
first------> 1 second-----> 2 third-----> 3 fouth----->
如果生成器函数不赋值变量,那么每次执行都是全新的生成器函数,并没有迭代的效果,如下:
def foo(): print('first------>') yield 1 print('second----->') yield 2 print('third----->') yield 3 print('fouth----->') print(foo().__next__()) print(foo().__next__()) print(foo().__next__()) 输出结果 first------> 1 first------> 1 first------> 1
使用print测试foo函数,会发现,同一时间输出的foo函数,内存地址并不同
print(foo(),foo(),foo()) 输出结果: <generator object foo at 0x00000251392F1E60> <generator object foo at 0x00000251392F1DB0> <generator object foo at 0x00000251392F1EB8>
生成器示例:一个yield返回多个值
def countdown(n): print('starting countdown') while n > 0: yield n n-=1 print('stop countdown') g=countdown(5) for i in g: print(i) 输出结果 starting countdown 5 4 3 2 1 stop countdown
生成器模拟linux命令:tail -f a.txt |grep 'error' |grep '404'
当在a.txt文件中输入字符串,如果包含error并且包含404,那么将打印出该行,其他不打印
import time def tail(filepath,encoding='utf-8'): with open(filepath,encoding=encoding) as f: f.seek(0,2) while True: # f.seek(0, 2) #不行 line=f.readline() if line: # print(line,end='') yield line else: time.sleep(0.5) def grep(lines,pattern): for line in lines: if pattern in line: # print(line) yield line g1=tail('a.txt') g2=grep(g1,'error') g3=grep(g2,'404') for i in g3: print(i)
三元表达式
简化代码量:比较两个数的大小,可以用以下if语句完成
x=2 y=3 if x > y: print(x) else: print(y)
使用三元表达式:可以简化成一行解决
res='x' if x > y else 'y' print(res)
三元表达式即 'x' if x > y else 'y'
当条件为真,那么输出条件左边的值,当条件为假则输出右边的值
示例:
def max2(x,y): # if x > y: # return x # else: # return y return x if x > y else y print(max2(1,2))
列表生成式
简化生成列表的代码量
如:将s='hello'的字符串转化成大写,并将每一个字符转化成列表元素,即['H','E','L','L','O']
普通循环代码:
s='hello' l=[] for i in s: res=i.upper() l.append(res) print(l)
列表解析代码:
s='hello' res=[i.upper() for i in s] print(res)
使用列表解析能够简化简单的代码生成
列表生成式说明:
示例:
l=[1,31,73,84,57,22] print([i for i in l if i > 50]) #l列表中大于50的元素生成一个新列表 print([i for i in l if i < 50]) #l列表中小于50的元素生成一个新列表
print([i for i in l if i > 20 and i < 50]) #l列表中大于20小于50的元素生成一个新列表
生成器表达式
类似于列表生成式,只不过将中括号换成小括号,每次执行next将输出一个元素,占用内存小,每次只占用一个元素的内存空间
g=(i for i in range(1000)) print(g) #生成器 print(next(g)) #每次执行next(g)即可输出一个元素 print(next(g)) print(next(g)) print(next(g)) 输出结果 <generator object <genexpr> at 0x00000205FFE91E60> 0 1 2 3