函数的执行时,*打散
函数的定义时,*聚合
from functools import wraps def wrapper(f): @wraps(f) def inner(*args,**kwargs): '''执行函数之前的相关操作''' ret = f(*args,**kwargs) '''执行函数之后的相关操作''' return ret return inner @wrapper def func1(*args): print(666) return args print(func1(*[1,2,3]))
一,函数的有用信息
1.函数名 使用__name__方法
2.函数的解释 使用__doc__方法获取
举个例子:
def func1(): """ 此函数是完成登陆的功能,参数分别是...作用。 :return: 返回值是登陆成功与否(True,False) """ print(666) # print(func1.__name__) # print(func1.__doc__) return True func1() print(func1.__name__) #获取函数名 print(func1.__doc__) #获取函数名注释说明
执行输出:
666
func1
此函数是完成登陆的功能,参数分别是...作用。
:return: 返回值是登陆成功与否(True,False)
这个有什么用呢?比如日志功能,需要打印出谁在什么时间,调用了什么函数,函数是干啥的,花费了多次时间,这个时候,就需要获取函数的有用信息了
带装饰器的函数
def wrapper(f): # f = func1 def inner(*args, **kwargs): # 聚合 # args (1,2,3) '''执行函数之前的相关操作''' ret = f(*args, **kwargs) # 打散 1,2,3 '''执行函数之后的相关操作''' return ret return inner @wrapper def func1(): """ 此函数是完成登陆的功能,参数分别是...作用。 :return: 返回值是登陆成功与否(True,False) """ print(666) return True func1() print(func1.__name__) print(func1.__doc__)
此函数是完成登陆的功能,参数分别是...作用。
:return: 返回值是登陆成功与否(True,False)
二, 带参数的装饰器
#带参数的装饰器 import time def timmer(*args,**kwargs): def wrapper(f): print(args,kwargs) #接收第一步的值 def inner(*args,**kwargs): if flag: start_time = time.time() ret = f(*args,**kwargs) time.sleep(0.3) end_time = time.time() print('此函数的执行效率{}'.format(end_time-start_time)) else: ret = f(*args,**kwargs) return ret return inner return wrapper flag = True @timmer(flag,2,3) #两部:1.timmer(flag,2,3)相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1) def func1(*args,**kwargs): return 666 print(func1())
执行输出:
(True, 2, 3) {}
此函数的执行效率0.300183
666
函数执行过程分析
import time #1.加载模块 def timmer(*args,**kwargs): #2.读取timer这个函数变量名到内存中 #5.接收参数True 2, 3 def wrapper(f): #8.f = func1 print(args,kwargs) #9.接收timmer函数的值True,2,3 def inner(*args,**kwargs): #10. 加载变量 13.执行函数inner if flag: #14.flag = True start_time = time.time() #15获取当前时间 ret = f(*args,**kwargs)#16执行func1 time.sleep(0.3) #19等待3秒 end_time = time.time() #20获取当前时间 print('此函数的执行效率{}'.format(end_time-start_time)) #21打印差值 else: ret = f(*args,**kwargs) #22返回给函数调用者func(1) return ret return inner #11.返回给函数调用者wrapper return wrapper #7.返回给函数调用者timmer(flag,2,3) flag = True #3.加载变量 @timmer(flag,2,3) #4.执行函数timeer(flag,2,3) 17.执行函数func1 两步:1.timmer(flag,2,3)相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1) def func1(*args,**kwargs): return 666 #返回给函数调用者 print(func1()) #12.执行函数
假定现在有100个函数,都加上了装饰器,增加了显示函数执行时间的功能,现在需要去掉!
怎能办?一行行代码去删除吗?太low了。
这个时候,直接在装饰器函数加一个参数即可。
import time flag = False def wrapper(f): def inner(*args,**kwargs): if flag: start_time = time.time() ret = f(*args,**kwargs) time.sleep(0.3) end_time = time.time() print('此函数的执行效率%f' % (end_time-start_time)) else: ret = f(*args, **kwargs) return ret return inner @wrapper def func1(*args,**kwargs): print(args,kwargs) return 666 print(func1())
现在需要关闭显示执行时间
直接将flag改成false
import time flag = False def wrapper(f): def inner(*args,**kwargs): if flag: start_time = time.time() ret = f(*args,**kwargs) time.sleep(0.3) end_time = time.time() print('此函数的执行效率%f' % (end_time-start_time)) else: ret = f(*args, **kwargs) return ret return inner @wrapper def func1(*args,**kwargs): print(args,kwargs) return 666 print(func1())
执行输出:
() {}
666
这样,所有调用的地方,就全部关闭了,非常方便
写装饰器,一般嵌套3层就可以了
实例二
a = 5 def func1(): a += 1 print(a) func1()
执行报错
这里函数对全局变量做了改变,是不允许操作的。
函数内部可以引用全局变量,不能修改。如果要修改,必须要global一下
a = 5 def func1(): global a a += 1 print(a) func1()
执行输出: 6
三,多个装饰器,装饰一个函数
def wrapper1(func): def inner1(): print('wrapper1,before func') func() print('wrapper1 ,after func') return inner1 def wrapper2(func): def inner2(): print('wrapper2 ,before func') func() print('wrapper2,after func') return inner2 @wrapper2 @wrapper1 def f(): print('in f') f()
执行输出:
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
执行顺序如下图:
多个装饰器,都是按照上图的顺序来的
今日练习作业:
1.
写函数,返回一个扑克牌列表,里面有
52
项,每一项是一个元组
例如:[(
'红心'
,
2
),(
'草花'
,
2
), …(
'黑桃'
,
'A'
)]
#实例一: #思路:使用for循环先遍历出红心,黑桃,梅花,方块,再将使用for循环变量1-13个数字 #步骤1:准备基础数据 #颜色 #扑克牌的4种颜色 colour = ['黑桃♠','红心♥','梅花♣','方块♦'] #牌面的值 card = list[range(2,11) + ['A','J','Q','K']]
#1.2使用for 循环遍历 # 颜色 colour = ['黑桃♠', '红心♥', '梅花♣', '方块♦'] # 牌面的值 card = list(range(2, 11)) + ['A', 'J', 'Q', 'K'] # for i in card: for j in colour: print((j,i))
执行输出:
('黑桃♠', 2)
('红心♥', 2)
('梅花♣', 2)
1.3封装成函数
def poker(*args, **kwargs): show_card = [] for i in kwargs['card']: for j in kwargs['colour']: show_card.append((j, i)) return show_card print(poker(colour=colour, card=card))
执行输出:
[('黑桃♠', 2), ('红心♥', 2), ('梅花♣', 2),...]
2.写函数,传入n个数,返回字典{'max':最大值,'min':最小值}
例如:min_max(2,5,7,8,4)
返回:{'max':8,'min':2}
2.1直接使用内置函数,可以得到最大值和最小值 a = (1,2,3) b = {'k1':1,'k2':2} print(max(a)) print(min(b.values()))
执行输出:
3
1
2.2封装成函数
def min_max(*args,**kwargs): dic = {'max':None,'min':None} number = [] #循环位置变量 for i in args: #这里是接收数据 for j in i: #这里是迭代数据,打散将每一个数字分成变量一个元素 number.append(j) #循环关键字变量 for k in kwargs.values(): number.append(k) #最大值和最小值 dic['max'] = max(number) dic['min'] = min(number) return dic print(min_max([2,3,4,5,6,9],a=8))
执行后输出:
{'max': 9, 'min': 2}
3.写函数,专门计算图形的面积
其中嵌套函数,计算圆的面积,正方形的面积和长方形的面积
调用函数area('圆形',圆半径) 返回圆的面积
调用函数area('正方形',边长) 返回正方形的面积
调用函数area('长方形',长,宽) 返回长方形的面积
def area():
def 计算长方形面积():
pass
def 计算正方形面积():
pass
def 计算圆形面积():
pass
先找出公式
长方形面积公式
S = ab
公式描述:公式中a,b分别为长方形的长和宽,S为长方形的面积。
正方形面积公式
S = a²
公式描述:公式中a为正方形边长,S为正方形面积。
圆的面积公式
S = πr²
公式描述:公式中r为圆的半径,π用3.14表示
def area(*args,**kwargs): #计算长方形面积 def rectangle(*args,**kwargs): #print(args) return args[0] * args[1] #计算正方形面积 def square(*args,**kwargs): return args[0] ** 2 #计算圆形面积 def circular(*args,**kwargs): return 3.14 * (args[0] ** 2) #判断参数 if args[0].strip() == '长方形': return rectangle(args[1],args[2]) elif args[0].strip() == '正方形': return square(args[1]) elif args[0].strip() == '圆形': return circular(args[1]) else: return '参数不正确!' ret1 = area('长方形',3,4) ret2 = area('正方形',5) ret3 = area('圆形',6) print(ret1) print(ret2) print(ret3)
def area(*args): # 判断参数 if args[0] == '长方形': def 计算长方形面积(): s = args[1] * args[2] return s return 计算长方形面积() elif args[0] == '正方形': def 计算正方形面积(): s = args[1] ** 2 return s return 计算正方形面积() elif args[0] == '圆形': def 计算圆形面积(): s = 3.14 * (args[1] ** 2) return s return 计算圆形面积() print(area('长方形', 2, 3)) print(area('正方形', 5)) print(area('圆形', 6))
给每个函数写一个记录日志的功能,
功能要求:每一次调用函数之前,要将函数名称,时间节点记录到log的日志中。
所需模块:
import time
struct_time = time.localtime()
print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))
#准备装饰器模版 def wrapper(f): def inner(*args,**kwargs): '''函数装饰前''' ret = f(*args,**kwargs) '''函数装饰之后''' return ret return inner
import time def wrapper(f): def inner(*args,**kwargs): '''被装饰函数之前''' ret = f(*args,**kwargs) '''被装饰函数之后''' struct_time = time.localtime() standard_time = time.localtime() print('函数名称:{} 时间节点:{} '.format(f.__name__, standard_time)) return ret return inner @wrapper def func1(): ''' 此函数是测试的 :return: ''' print(666) time.sleep(0.3) return True func1()
加入些日志功能:
import time def wrapper(f): def inner(*args,**kwargs): '''被装饰函数之前''' ret = f(*args,**kwargs) '''被装饰函数之后''' struct_time = time.localtime() standard_time = time.localtime() #写日志功能加入 with open('function_log.txt', encoding='utf-8', mode='a+') as f1: f1.write('函数名称:{} 时间节点:{} '.format(f.__name__, standard_time)) return ret return inner @wrapper def func1(): ''' 此函数是测试的 :return: ''' print(666) time.sleep(0.3) return True func1()
def wrapper(func): def inner(*args,**kwargs): struct_time = time.localtime() time_now = time.strftime("%Y-%m-%d %H:%M:%S", struct_time) with open('log', encoding='utf-8', mode='a') as f1: f1.write('在时间是%s,执行了%s函数 ' % (time_now, func.__name__)) ret = func(*args, **kwargs) '''函数执行之后操作''' return ret return inner @wrapper def func1(): time.sleep(1) print(6666) @wrapper def func2(): time.sleep(2) print(7777) func1() func2()
写函数,传入一个参数n,返回n的阶乘
例如: cal(7)
def func3(n): count = 1 for i in range(n,0,-1): count = count * i return count print(func3(7))
执行后输出:
5040
编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),
# 要求登录成功一次(三次机会),后续的函数都无需再输入用户名和密码
准备雏形:
def check_login(func): #检查登陆的装饰器 def inner(*args,**kwargs): '''函数被装饰之前''' ret = func(*args,**kwargs) '''函数被装饰之后''' return ret return inner def index(): print("welcome to index page") @check_login def home(): #用户主页 print("welcome to home page") @check_login def bbs(): #bbs页面 print("welcome to bbs page")
#全局变量,用户状态 dic = { 'username':None, 'status':False, } #错误次数 i = 0 def wrapper(func): def inner(*args, **kwargs): #判断登录状态是否为True if dic['status']: #执行被装饰行函数 ret = func(*args, **kwargs) return ret else: #这里需要修改全局变量,要global一下 global i while i < 3: username = input('请输入用户名:').strip() password = input('请输入密码:').strip() with open('register_msg',encoding='utf-8') as f1: for j in f1: j_li = j.strip().split() # ['张三','123'] if username == j_li[0] and password == j_li[1]: #修改全局变量 dic['username'] = username dic['status'] = True ret = func(*args, **kwargs) return ret else: print('账号或者密码错误,请重新输入%s机会' % (2-i)) i += 1 return inner @wrapper def article(): print('文章') @wrapper def diary(): print('日记') @wrapper def comment(): print('评论') @wrapper def file(): print('文件') article() diary() comment() file()