python全栈学习--day12(函数高级应用-带参数的装饰器,多个装饰器装饰一个函数)...
函數的執行時,*打散
函數的定義時,*聚合
from functools import wrapsdef wrapper(f):@wraps(f)def inner(*args,**kwargs):'''執行函數之前的相關操作'''ret = f(*args,**kwargs)'''執行函數之后的相關操作'''return retreturn 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 = func1def inner(*args, **kwargs): # 聚合# args (1,2,3)'''執行函數之前的相關操作'''ret = f(*args, **kwargs) # 打散 1,2,3'''執行函數之后的相關操作'''return retreturn inner@wrapper def func1():"""此函數是完成登陸的功能,參數分別是...作用。:return: 返回值是登陸成功與否(True,False)"""print(666)return Truefunc1() 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 retreturn innerreturn 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, 3def wrapper(f): #8.f = func1print(args,kwargs) #9.接收timmer函數的值True,2,3def inner(*args,**kwargs): #10. 加載變量 13.執行函數innerif flag: #14.flag = Truestart_time = time.time() #15獲取當前時間ret = f(*args,**kwargs)#16執行func1time.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 retreturn inner #11.返回給函數調用者wrapperreturn 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 retreturn 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 retreturn inner@wrapper def func1(*args,**kwargs):print(args,kwargs)return 666 print(func1())
執行輸出:
() {}
666
?
這樣,所有調用的地方,就全部關閉了,非常方便
寫裝飾器,一般嵌套3層就可以了
實例二
a = 5 def func1():a += 1print(a) func1()執行報錯
這里函數對全局變量做了改變,是不允許操作的。
函數內部可以引用全局變量,不能修改。如果要修改,必須要global一下
a = 5 def func1():global aa += 1print(a) func1()執行輸出: 6
三,多個裝飾器,裝飾一個函數
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()
執行輸出:
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}
執行輸出:
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 dicprint(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 = a2
公式描述:公式中a為正方形邊長,S為正方形面積。
圓的面積公式
S = πr2
公式描述:公式中r為圓的半徑,π用3.14表示
def area(*args):# 判斷參數if args[0] == '長方形':def 計算長方形面積():s = args[1] * args[2]return sreturn 計算長方形面積()elif args[0] == '正方形':def 計算正方形面積():s = args[1] ** 2return sreturn 計算正方形面積()elif args[0] == '圓形':def 計算圓形面積():s = 3.14 * (args[1] ** 2)return sreturn 計算圓形面積()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))
import time def wrapper(f):def inner(*args,**kwargs):'''被裝飾函數之前'''ret = f(*args,**kwargs)'''被裝飾函數之后'''struct_time = time.localtime()standard_time = time.localtime()print('函數名稱:{} 時間節點:{}\n'.format(f.__name__, standard_time))return retreturn 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('函數名稱:{} 時間節點:{}\n'.format(f.__name__, standard_time))return retreturn 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函數\n' % (time_now, func.__name__))ret = func(*args, **kwargs)'''函數執行之后操作'''return retreturn 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 = 1for i in range(n,0,-1):count = count * ireturn count print(func3(7))
執行后輸出:
5040
?
編寫裝飾器,為多個函數加上認證的功能(用戶的賬號密碼來源于文件),
# 要求登錄成功一次(三次機會),后續的函數都無需再輸入用戶名和密碼
準備雛形:
def check_login(func): #檢查登陸的裝飾器def inner(*args,**kwargs):'''函數被裝飾之前'''ret = func(*args,**kwargs)'''函數被裝飾之后'''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")#全局變量,用戶狀態 dic = {'username':None,'status':False, } #錯誤次數 i = 0def wrapper(func):def inner(*args, **kwargs):#判斷登錄狀態是否為Trueif dic['status']:#執行被裝飾行函數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機會' % (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()
?
?
轉載于:https://www.cnblogs.com/haowen980/p/8709844.html
總結
以上是生活随笔為你收集整理的python全栈学习--day12(函数高级应用-带参数的装饰器,多个装饰器装饰一个函数)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大数据爬虫前奏之Html和Css学习
- 下一篇: 选择排序法对数组进行排序