python一定会用到装饰器
1 # 装饰器 2 # 在原有的函数前后增加功能,且不改变原函数的调用方式 3 4 # 计算一个函数的运行时间 5 # import time 6 # def timmer(f): 7 # def inner(*args,**kwargs): 8 # start_time = time.time() 9 # ret = f(*args,**kwargs) 10 # end_time = time.time() 11 # print(end_time - start_time) 12 # return ret 13 # return inner 14 # 15 # @timmer # func = timmer(func) 16 # def func(a,b): 17 # print('begin func',a) 18 # time.sleep(0.1) 19 # print('end func',b) 20 # return True 21 # 22 # ret = func(1,2) #--> inner() 23 24 25 # def timmer(f): 26 # def inner(*args,**kwargs): 27 # 28 # ret = f(*args,**kwargs) 29 # 30 # return ret 31 # return inner
1.装饰器的进阶
1.设计装饰器确认是否生效 定义一个装饰器传参数
outer()
1 # 进阶的需求 2 # 第一种情况 3 # 500个函数 4 # 你可以设计你的装饰器 来确认是否生效 5 6 # import time 7 # FLAG = True 8 # def outer(flag): 9 # def timmer(f): 10 # def inner(*args,**kwargs): 11 # if flag == True: 12 # start_time = time.time() 13 # ret = f(*args,**kwargs) 14 # end_time = time.time() 15 # print(end_time - start_time) 16 # else: 17 # ret = f(*args, **kwargs) 18 # return ret 19 # return inner 20 # return timmer 21 # 22 # @outer(FLAG) # func = timmer(func) 23 # def func(a,b): 24 # print('begin func',a) 25 # time.sleep(0.1) 26 # print('end func',b) 27 # return True 28 # 29 # func(1,2)
2.装饰器 登录 记录日志
1 # 第二种情况 2 def wrapper1(func): 3 def inner1(): 4 print('wrapper1 ,before func') 5 func() 6 print('wrapper1 ,after func') 7 return inner1 8 9 def wrapper2(func): 10 def inner2(): 11 print('wrapper2 ,before func') 12 func() 13 print('wrapper2 ,after func') 14 return inner2 15 16 @wrapper2 17 @wrapper1 18 def f(): 19 print('in f') 20 21 # f()
自动登录!@login 单点登录(不加timer时)
登录,计算index和manager执行时间 :在写一个装饰器timer
多个装饰器,从下开始执行
1 # 装饰器 登录 记录日志 2 import time 3 login_info = {'alex':False} 4 def login(func): # manager 5 def inner(name): 6 if login_info[name] != True: 7 user = input('user :') 8 pwd = input('pwd :') 9 if user == 'alex' and pwd == 'alex3714': 10 login_info[name] = True 11 if login_info[name] == True: 12 ret = func(name) # timmer中的inner 13 return ret 14 return inner 15 16 def timmer(f): 17 def inner(*args,**kwargs): 18 start_time = time.time() 19 ret = f(*args,**kwargs) # 调用被装饰的方法 20 end_time = time.time() # 21 print(end_time - start_time) 22 return ret 23 return inner 24 25 @login 26 @timmer 27 def index(name): 28 print('欢迎%s来到博客园首页~'%name) 29 30 @login 31 @timmer # manager = login(manager) 32 def manager(name): 33 print('欢迎%s来到博客园管理页~'%name) 34 35 index('alex') 36 index('alex') 37 manager('alex') 38 manager('alex') 39 40 # 计算index 和 manager的执行时间
2.迭代器
从列表中取值
可迭代的
可迭代协议:__iter__方法
迭代器协议:__iter__和__next__方法
iter
while True
try---except异常处理
迭代器节省内存,快 iterable 可迭代的 iterator迭代器
py2 range
py3 range
迭代器特性:惰性运算
小例子
for line in f:(f至少是可迭代的)
列表字典 元祖字符串 集合 range 文件句柄 enumerate
1 # 迭代器 2 # 如何从列表、字典中取值的 3 # index索引 ,key 4 # for循环 5 # 凡是可以使用for循环取值的都是可迭代的 6 # 可迭代协议 :内部含有__iter__方法的都是可迭代的 7 # 迭代器协议 :内部含有__iter__方法和__next__方法的都是迭代器 8 # print(dir([1,2,3])) 9 # lst_iter = [1,2,3].__iter__() 10 # print(lst_iter.__next__()) 11 # print(lst_iter.__next__()) 12 # print(lst_iter.__next__()) 13 # for i in [1,2,3]: # [1,2,3].__iter__() 14 # print(i) 15 # l = [1,2,3] 16 # lst_iter = iter(l) # l.__iter__() 17 # while True: 18 # try: 19 # print(next(lst_iter)) # lst_iter.__next__() 20 # except StopIteration: 21 # break 22 23 # 什么是可迭代的 24 # 什么是迭代器 迭代器 = iter(可迭代的),自带一个__next__方法 25 # 可迭代 最大的优势 节省内存 26 # from collections import Iterable,Iterator 27 # print(range(100000000)) #range(0, 100000000) 28 # print(isinstance(range(100000000),Iterable)) #True 29 # print(isinstance(range(100000000),Iterator)) #False 30 # py2 range 不管range多少 会生成一个列表 这个列表将用来存储所有的值 31 # py3 range 不管range多少 都不会实际的生成任何一个值 32 # 迭代器的优势: 33 # 节省内存 34 # 取一个值就能进行接下来的计算 ,而不需要等到所有的值都计算出来才开始接下来的运算 —— 快 35 # 迭代器的特性:惰性运算 36 37 # f = open() 38 # for line in f: 39 40 # 列表 字典 元组 字符串 集合 range 文件句柄 enumerate
3.生成器generator
自己写的迭代器 就是一个生成器
两种自己写生成器(迭代器)的机制:生成器函数 生成器表达式
做衣服的例子 2000000 分批取
# 200 0000 # 牛翔 200 0000 # 40期 # 赵英杰 200 0000 # 21 60 60件衣服 # 200 0000 - 60 # 500期 0 # 501 # def cloth(num): # ret = [] # for i in range(num): # ret.append('cloth%s'%i) # return ret
yield凡是带有yield的函数就是生成器函数
生成器函数的调用不会触发代码的执行,而是返回一个生成器(迭代器) 加next取值
yield记录当前位置,等下一个next触发
1 # 凡是带有yield的函数就是一个生成器函数 2 # def func(): 3 # print('****') 4 # yield 1 5 # print('^^^^') 6 # yield 2 # 记录当前所在的位置,等待下一次next来触发函数的状态 7 # 8 # g = func() 9 # print('--',next(g)) #**** 10 #-- 1 11 # print('--',next(g)) #^^^^ 12 #-- 2 13 # 生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器) 14 # 想要生成器函数执行,需要用next 15 # def cloth_g(num): 16 # for i in range(num): 17 # yield 'cloth%s'%i 18 # 19 # g = cloth_g(1000) 20 # print(next(g)) #cloth0 21 # print(next(g)) #cloth1 22 # print(next(g)) #cloth2
生成器函数
多个next例子
使用生成器监听文件输入的例子,图片未保存看视频! 写入文件需要保存(无法用函数去做,函数无法监听)----实现记录日志
mac本中关闭文件才认为保存。
1 # 使用生成器监听文件输入的例子 2 # import time 3 # def listen_file(): 4 # with open('userinfo') as f: 5 # while True: 6 # line = f.readline() 7 # if line.strip(): 8 # yield line.strip() 9 # time.sleep(0.1) 10 # 11 # g = listen_file() 12 # for line in g: 13 # print(line)
send关键字:例子
定义:在执行next的过程中 传递一个参数 给生成器函数的内部
分析执行图片
向内部传参
send 不能用在第一次传值,必须next;send传给yield后的返回值
1 # send关键字 2 # def func(): 3 # print(11111) 4 # ret1 = yield 1 5 # print(22222,'ret1 :',ret1) 6 # ret2 = yield 2 7 # print(33333,'ret2 :',ret2) 8 # yield 3 9 # 10 # g = func() 11 # ret = next(g) 12 # print(ret) 13 # print(g.send('alex')) # 在执行next的过程中 传递一个参数 给生成器函数的内部 14 # print(g.send('金老板')) 15 # 想生成器中传递值 有一个激活的过程 第一次必须要用next触发这个生成器
#例子 计算移动平均值!!
月度的天平均收入 def average():
注意开始day=0报错的处理 分析图片
1 # 例子 2 # 计算移动平均值 3 # 12 13 15 18 4 # 月度 的 天平均收入 5 # def average(): 6 # sum_money = 0 7 # day = 0 8 # avg = 0 9 # while True: 10 # money = yield avg 11 # sum_money += money 12 # day += 1 13 # avg = sum_money/day 14 # 15 # g = average() 16 # next(g) 17 # print(g.send(200)) 18 # print(g.send(300)) 19 # print(g.send(600))
预激生成器 next(g) 放在装饰器中 看思考题面试最后一道
1 # 预激生成器 2 # def init(func): 3 # def inner(*args,**kwargs): 4 # ret = func(*args,**kwargs) 5 # next(ret) # 预激活 6 # return ret 7 # return inner 8 # 9 # @init 10 # def average(): 11 # sum_money = 0 12 # day = 0 13 # avg = 0 14 # while True: 15 # money = yield avg 16 # sum_money += money 17 # day += 1 18 # avg = sum_money/day 19 # 20 # g = average() 21 # print(g.send(200)) 22 # print(g.send(300)) 23 # print(g.send(600))
yield from
例子 range从0开始取值
yield from range(5) ---->
for i in range(5):
print(i)
g=generator_func() 与放print中区别,放在print中一直打印0
g取得不同的内存
1 # yield from 2 def generator_func(): 3 yield from range(5) 4 yield from 'hello' 5 # for i in range(5): 6 # yield i 7 # for j in 'hello': 8 # yield j 9 10 # g = generator_func() 11 # for i in generator_func(): 12 # print(i) 13 14 # g1 = generator_func() 15 # g2 = generator_func() 16 # next(generator_func()) 17 # next(generator_func())
如何从生成器取值
next :随时停止,最后一次会报错,不知道在哪儿停
for循环:从头到尾遍历一次,不遇到break、return不停止
list、tuple:把所有数据类型都放在list中,浪费内存
# 如何从生成器中取值 # 第一种 :next 随时都可以停止 最后一次会报错 # print(next(g)) # print(next(g)) # 第二种 :for循环 从头到尾遍历一次 不遇到break、return不会停止 # for i in g: # print(i) # 第三种 :list tuple 数据类型的强转 会把所有的数据都加载到内存里 非常的浪费内存 # print(g) # print(list(g))
总结:有yield。。。
生成器用途2个图片
1 # 生成器函数 是我们python程序员实现迭代器的一种手段 2 # 主要特征是 在函数中 含有yield 3 # 调用一个生成器函数 不会执行这个函数中的带码 只是会获得一个生成器(迭代器) 4 # 只有从生成器中取值的时候,才会执行函数内部的带码,且每获取一个数据才执行得到这个数据的带码 5 # 获取数据的方式包括 next send 循环 数据类型的强制转化 6 # yield返回值的简便方法,如果本身就是循环一个可迭代的,且要把可迭代数据中的每一个元素都返回 可以用yield from 7 # 使用send的时候,在生成器创造出来之后需要进行预激,这一步可以使用装饰器完成 8 # 生成器的特点 : 节省内存 惰性运算 9 # 生成器用来解决 内存问题 和程序功能之间的解耦
生成器表达式
推导过程例子
完整的列表推导式
#30以内能被3整除的数
print([i for i in range(30) if i%3==0])
#30以内能被3整除的数的平方
print([i**2 for i in range(30) if i%3==0])
两个for也可以
研究集合、字典推导式---不常用
1 # 列表推倒式 2 # new_lst = [] 3 # for i in range(10): 4 # new_lst.append(i**2) 5 # print(new_lst) 6 # print([i**2 for i in range(10)]) 7 # l = [1,2,3,-5,6,20,-7] 8 # print([i%2 for i in range(10)]) 9 # l = [1,2,3,-5,6,20,-7] 10 # print([num for num in l if num%2 == 1]) 11 12 # 30以内所有能被3整除的数 13 # print([i for i in range(30) if i%3 ==0]) 14 # 15 # 30以内所有能被3整除的数的平方 16 # print([i**2 for i in range(30) if i%3 ==0]) 17 18 # 找到嵌套列表中名字含有两个‘e’的所有名字 19 # names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], 20 # ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] 21 # print([name for name_lst in names for name in name_lst if name.count('e') == 2])
列表推导式[] 排序的时候
生成器表达式() 数据量庞大的时候用
1 # 生成器表达式 2 # l = [i for i in range(30) if i%3 ==0] # 列表推倒式 排序的时候 3 # g = (i for i in range(30) if i%3 ==0) # 生成器表达式 庞大数据量的时候 使用生成器表达式 4 # print(l) 5 # print(g) 6 # for i in g:print(i)
面试题
1.list时真正执行 一个生成器只能取一次
1 # def demo(): 2 # for i in range(4): 3 # yield i 4 # 5 # g=demo() 6 # 7 # g1=(i for i in g) 8 # g2=(i for i in g1) 9 # 10 # print(list(g1)) #[0,1,2,3] 11 # print(list(g2)) #[]
2.[20,21,22,23]重点理解生成器什么时候执行!!
生成器在不找它要值的时候始终不执行
执行时候,要以执行变量值为准
[1,3,10] [30,31,32,33]
1 # mianshiti2 2 # def add(n,i): 3 # return n+i 4 # 5 # def test(): 6 # for i in range(4): 7 # yield i 8 # 9 # g=test() 10 # for n in [1,10]: 11 # g=(add(n,i) for i in g) 12 # 13 # print(list(g))
3.面试题3,看懂即可!
1 import os 2 3 def init(func): 4 def wrapper(*args,**kwargs): 5 g=func(*args,**kwargs) 6 next(g) 7 return g 8 return wrapper 9 10 @init 11 def list_files(target): 12 while 1: 13 dir_to_search=yield 14 for top_dir,dir,files in os.walk(dir_to_search): 15 for file in files: 16 target.send(os.path.join(top_dir,file)) 17 @init 18 def opener(target): 19 while 1: 20 file=yield 21 fn=open(file) 22 target.send((file,fn)) 23 @init 24 def cat(target): 25 while 1: 26 file,fn=yield 27 for line in fn: 28 target.send((file,line)) 29 30 @init 31 def grep(pattern,target): 32 while 1: 33 file,line=yield 34 if pattern in line: 35 target.send(file) 36 @init 37 def printer(): 38 while 1: 39 file=yield 40 if file: 41 print(file) 42 43 g=list_files(opener(cat(grep('python',printer())))) 44 45 g.send('/test1') 46 47 协程应用:grep -rl /dir