python全栈学习--day12(函数高级应用-带参数的装饰器,多个装饰器装饰一个函数)...
函數(shù)的執(zhí)行時,*打散
函數(shù)的定義時,*聚合
from functools import wrapsdef wrapper(f):@wraps(f)def inner(*args,**kwargs):'''執(zhí)行函數(shù)之前的相關(guān)操作'''ret = f(*args,**kwargs)'''執(zhí)行函數(shù)之后的相關(guān)操作'''return retreturn inner @wrapper def func1(*args):print(666)return args print(func1(*[1,2,3])) 一,函數(shù)的有用信息1.函數(shù)名 使用__name__方法
2.函數(shù)的解釋 使用__doc__方法獲取
舉個例子: def func1():"""此函數(shù)是完成登陸的功能,參數(shù)分別是...作用。:return: 返回值是登陸成功與否(True,False)"""print(666)# print(func1.__name__)# print(func1.__doc__)return True func1() print(func1.__name__) #獲取函數(shù)名 print(func1.__doc__) #獲取函數(shù)名注釋說明
執(zhí)行輸出:
666
func1
此函數(shù)是完成登陸的功能,參數(shù)分別是...作用。
:return: 返回值是登陸成功與否(True,False)
這個有什么用呢?比如日志功能,需要打印出誰在什么時間,調(diào)用了什么函數(shù),函數(shù)是干啥的,花費(fèi)了多次時間,這個時候,就需要獲取函數(shù)的有用信息了
帶裝飾器的函數(shù)
def wrapper(f): # f = func1def inner(*args, **kwargs): # 聚合# args (1,2,3)'''執(zhí)行函數(shù)之前的相關(guān)操作'''ret = f(*args, **kwargs) # 打散 1,2,3'''執(zhí)行函數(shù)之后的相關(guān)操作'''return retreturn inner@wrapper def func1():"""此函數(shù)是完成登陸的功能,參數(shù)分別是...作用。:return: 返回值是登陸成功與否(True,False)"""print(666)return Truefunc1() print(func1.__name__) print(func1.__doc__) 此函數(shù)是完成登陸的功能,參數(shù)分別是...作用。
:return: 返回值是登陸成功與否(True,False)
?
二, 帶參數(shù)的裝飾器
#帶參數(shù)的裝飾器 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('此函數(shù)的執(zhí)行效率{}'.format(end_time-start_time))else:ret = f(*args,**kwargs)return retreturn innerreturn wrapper flag = True @timmer(flag,2,3) #兩部:1.timmer(flag,2,3)相當(dāng)于執(zhí)行wrapper 2.@wrapper 裝飾器 func1 = wrapper(func1) def func1(*args,**kwargs):return 666 print(func1())
執(zhí)行輸出:
(True, 2, 3) {}
此函數(shù)的執(zhí)行效率0.300183
666
函數(shù)執(zhí)行過程分析
import time #1.加載模塊 def timmer(*args,**kwargs): #2.讀取timer這個函數(shù)變量名到內(nèi)存中 #5.接收參數(shù)True 2, 3def wrapper(f): #8.f = func1print(args,kwargs) #9.接收timmer函數(shù)的值True,2,3def inner(*args,**kwargs): #10. 加載變量 13.執(zhí)行函數(shù)innerif flag: #14.flag = Truestart_time = time.time() #15獲取當(dāng)前時間ret = f(*args,**kwargs)#16執(zhí)行func1time.sleep(0.3) #19等待3秒end_time = time.time() #20獲取當(dāng)前時間print('此函數(shù)的執(zhí)行效率{}'.format(end_time-start_time)) #21打印差值else:ret = f(*args,**kwargs) #22返回給函數(shù)調(diào)用者func(1)return retreturn inner #11.返回給函數(shù)調(diào)用者wrapperreturn wrapper #7.返回給函數(shù)調(diào)用者timmer(flag,2,3) flag = True #3.加載變量 @timmer(flag,2,3) #4.執(zhí)行函數(shù)timeer(flag,2,3) 17.執(zhí)行函數(shù)func1 兩步:1.timmer(flag,2,3)相當(dāng)于執(zhí)行wrapper 2.@wrapper 裝飾器 func1 = wrapper(func1) def func1(*args,**kwargs):return 666 #返回給函數(shù)調(diào)用者 print(func1()) #12.執(zhí)行函數(shù)
假定現(xiàn)在有100個函數(shù),都加上了裝飾器,增加了顯示函數(shù)執(zhí)行時間的功能,現(xiàn)在需要去掉!
怎能辦?一行行代碼去刪除嗎?太low了。
這個時候,直接在裝飾器函數(shù)加一個參數(shù)即可。
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('此函數(shù)的執(zhí)行效率%f' % (end_time-start_time))else:ret = f(*args, **kwargs)return retreturn inner@wrapper def func1(*args,**kwargs):print(args,kwargs)return 666 print(func1())
現(xiàn)在需要關(guān)閉顯示執(zhí)行時間
直接將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('此函數(shù)的執(zhí)行效率%f' % (end_time-start_time))else:ret = f(*args, **kwargs)return retreturn inner@wrapper def func1(*args,**kwargs):print(args,kwargs)return 666 print(func1())
執(zhí)行輸出:
() {}
666
?
這樣,所有調(diào)用的地方,就全部關(guān)閉了,非常方便
寫裝飾器,一般嵌套3層就可以了
實(shí)例二
a = 5 def func1():a += 1print(a) func1()執(zhí)行報錯
這里函數(shù)對全局變量做了改變,是不允許操作的。
函數(shù)內(nèi)部可以引用全局變量,不能修改。如果要修改,必須要global一下
a = 5 def func1():global aa += 1print(a) func1()執(zhí)行輸出: 6
三,多個裝飾器,裝飾一個函數(shù)
def wrapper1(func):def inner1():print('wrapper1,before func')func()print('wrapper1 ,after func')return inner1def wrapper2(func):def inner2():print('wrapper2 ,before func')func()print('wrapper2,after func')return inner2@wrapper2 @wrapper1 def f():print('in f') f()
執(zhí)行輸出:
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
執(zhí)行順序如下圖:
多個裝飾器,都是按照上圖的順序來的
今日練習(xí)作業(yè):
1.寫函數(shù),返回一個撲克牌列表,里面有52項(xiàng),每一項(xiàng)是一個元組
例如:[('紅心',2),('草花',2), …('黑桃','A')] #實(shí)例一: #思路:使用for循環(huán)先遍歷出紅心,黑桃,梅花,方塊,再將使用for循環(huán)變量1-13個數(shù)字 #步驟1:準(zhǔn)備基礎(chǔ)數(shù)據(jù) #顏色 #撲克牌的4種顏色 colour = ['黑桃?','紅心?','梅花?','方塊?'] #牌面的值 card = list[range(2,11) + ['A','J','Q','K']]#1.2使用for 循環(huán)遍歷 # 顏色 colour = ['黑桃?', '紅心?', '梅花?', '方塊?']# 牌面的值 card = list(range(2, 11)) + ['A', 'J', 'Q', 'K'] # for i in card:for j in colour:print((j,i))
執(zhí)行輸出:
('黑桃?', 2)
('紅心?', 2)
('梅花?', 2)
1.3封裝成函數(shù)
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))
執(zhí)行輸出:
[('黑桃?', 2), ('紅心?', 2), ('梅花?', 2),...]
2.寫函數(shù),傳入n個數(shù),返回字典{'max':最大值,'min':最小值}
例如:min_max(2,5,7,8,4)
返回:{'max':8,'min':2}
執(zhí)行輸出:
3
1
?
2.2封裝成函數(shù)
def min_max(*args,**kwargs):dic = {'max':None,'min':None}number = []#循環(huán)位置變量for i in args: #這里是接收數(shù)據(jù)for j in i: #這里是迭代數(shù)據(jù),打散將每一個數(shù)字分成變量一個元素number.append(j)#循環(huán)關(guān)鍵字變量for k in kwargs.values():number.append(k)#最大值和最小值dic['max'] = max(number)dic['min'] = min(number)return dicprint(min_max([2,3,4,5,6,9],a=8))執(zhí)行后輸出:
{'max': 9, 'min': 2}
3.寫函數(shù),專門計(jì)算圖形的面積
其中嵌套函數(shù),計(jì)算圓的面積,正方形的面積和長方形的面積
調(diào)用函數(shù)area('圓形',圓半徑) 返回圓的面積
調(diào)用函數(shù)area('正方形',邊長) 返回正方形的面積
調(diào)用函數(shù)area('長方形',長,寬) 返回長方形的面積
def area():
def 計(jì)算長方形面積():
pass
def 計(jì)算正方形面積():
pass
def 計(jì)算圓形面積():
pass
先找出公式
長方形面積公式
S = ab
公式描述:公式中a,b分別為長方形的長和寬,S為長方形的面積。
正方形面積公式
S = a2
公式描述:公式中a為正方形邊長,S為正方形面積。
圓的面積公式
S = πr2
公式描述:公式中r為圓的半徑,π用3.14表示
def area(*args):# 判斷參數(shù)if args[0] == '長方形':def 計(jì)算長方形面積():s = args[1] * args[2]return sreturn 計(jì)算長方形面積()elif args[0] == '正方形':def 計(jì)算正方形面積():s = args[1] ** 2return sreturn 計(jì)算正方形面積()elif args[0] == '圓形':def 計(jì)算圓形面積():s = 3.14 * (args[1] ** 2)return sreturn 計(jì)算圓形面積()print(area('長方形', 2, 3)) print(area('正方形', 5)) print(area('圓形', 6))
給每個函數(shù)寫一個記錄日志的功能,
功能要求:每一次調(diào)用函數(shù)之前,要將函數(shù)名稱,時間節(jié)點(diǎn)記錄到log的日志中。
所需模塊:
import time
struct_time = time.localtime()
print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))
import time def wrapper(f):def inner(*args,**kwargs):'''被裝飾函數(shù)之前'''ret = f(*args,**kwargs)'''被裝飾函數(shù)之后'''struct_time = time.localtime()standard_time = time.localtime()print('函數(shù)名稱:{} 時間節(jié)點(diǎn):{}\n'.format(f.__name__, standard_time))return retreturn inner @wrapper def func1():'''此函數(shù)是測試的:return:'''print(666)time.sleep(0.3)return True func1()
加入些日志功能:
import time def wrapper(f):def inner(*args,**kwargs):'''被裝飾函數(shù)之前'''ret = f(*args,**kwargs)'''被裝飾函數(shù)之后'''struct_time = time.localtime()standard_time = time.localtime()#寫日志功能加入with open('function_log.txt', encoding='utf-8', mode='a+') as f1:f1.write('函數(shù)名稱:{} 時間節(jié)點(diǎn):{}\n'.format(f.__name__, standard_time))return retreturn inner @wrapper def func1():'''此函數(shù)是測試的: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,執(zhí)行了%s函數(shù)\n' % (time_now, func.__name__))ret = func(*args, **kwargs)'''函數(shù)執(zhí)行之后操作'''return retreturn inner@wrapper def func1():time.sleep(1)print(6666) @wrapper def func2():time.sleep(2)print(7777) func1() func2()
寫函數(shù),傳入一個參數(shù)n,返回n的階乘
例如: cal(7)
def func3(n):count = 1for i in range(n,0,-1):count = count * ireturn count print(func3(7))
執(zhí)行后輸出:
5040
?
編寫裝飾器,為多個函數(shù)加上認(rèn)證的功能(用戶的賬號密碼來源于文件),
# 要求登錄成功一次(三次機(jī)會),后續(xù)的函數(shù)都無需再輸入用戶名和密碼
準(zhǔn)備雛形:
def check_login(func): #檢查登陸的裝飾器def inner(*args,**kwargs):'''函數(shù)被裝飾之前'''ret = func(*args,**kwargs)'''函數(shù)被裝飾之后'''return retreturn innerdef 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")#全局變量,用戶狀態(tài) dic = {'username':None,'status':False, } #錯誤次數(shù) i = 0def wrapper(func):def inner(*args, **kwargs):#判斷登錄狀態(tài)是否為Trueif dic['status']:#執(zhí)行被裝飾行函數(shù)ret = func(*args, **kwargs)return retelse:#這里需要修改全局變量,要global一下global iwhile 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'] = usernamedic['status'] = Trueret = func(*args, **kwargs)return retelse:print('賬號或者密碼錯誤,請重新輸入%s機(jī)會' % (2-i))i += 1return inner@wrapper def article():print('文章')@wrapper def diary():print('日記')@wrapper def comment():print('評論')@wrapper def file():print('文件')article() diary() comment() file()
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/haowen980/p/8709844.html
總結(jié)
以上是生活随笔為你收集整理的python全栈学习--day12(函数高级应用-带参数的装饰器,多个装饰器装饰一个函数)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大数据爬虫前奏之Html和Css学习
- 下一篇: 选择排序法对数组进行排序