【24】Python裝飾器筆記
阿新 • • 發佈:2018-02-04
put 訪問 img elif 分享 sse pass 源代碼 local 裝飾器
定義:本職是函數,(裝飾其他函數)就是為其他函數添加附加功能。
原則:
1.不能修改被裝飾的函數的源代碼
2.不能修改被裝飾函數的調用的方式
定義:本職是函數,(裝飾其他函數)就是為其他函數添加附加功能。
原則:
1.不能修改被裝飾的函數的源代碼
2.不能修改被裝飾函數的調用的方式
先來一個直觀感受 import time def timmer(func): ## def warpper(*args,**kwargs): start_time=time.time() func() ##run test1() stop_time=time.time() print("the func time is %s"%(start_time-stop_time)) return warpper @timmer #@加函數名,即可調用函數 def test1(): ###源代碼 time.sleep(3) print("in the test1") test1()
實現裝飾器的知識儲備:
1.函數即"變量"
2.高階函數
3.嵌套函數(函數裏面def聲明一個函數叫嵌套函數,調用函數不叫嵌套)
下面進行一波實驗:如下三種結果(驗證1.函數即“變量”) A.輸出報錯沒有bar函數 def foo(): print("in the foo") bar() foo() B.成功 def bar(): print("in the bar") def foo(): print("in the foo") bar() foo() C.輸出報錯,沒找到定義的bar函數 def foo(): print("in the foo") bar() foo() def bar(): print("in the bar")
在將函數即“變量”的時候,先講下python內存存儲變量的機制。
當設定一個變量x=1時,內存看成一個大house,這時候大house會騰出一個房間將變量值1放入這個房間,並貼上x的門牌號。
如果是x=1,y=x,那就是變量值1這個房間將會有兩個門牌號,即x&y。如圖所示:
而在python內存的回收機制中,當你的房間沒有門牌號時,它就會默認回收。這樣可以節約空間。而當兩個或多個變量值都一樣時,它不會給你創建N個房間,而是同一個房間內貼上N個門牌號。
凡是也有例外,有人就會說了,那就不會有沒有變量名的變量了嗎?這個在python中,還真有即匿名函數lambda。當lambda x:x*3,結果是占用的內存地址。
這裏的
print(“in the poo”)
bar()
就是函數體相當於變量存放在內存中。poo()就是門牌號,當執行A時之所以會報錯,就是因為沒有找到bar的函數體。而C雖然定義了bar()但是定義的位置不對,函數都是從上往下讀取,當執行poo()之前並沒有定義,所以會報錯找不到bar
2.高階函數(又分以下兩種)
a:把一個函數名當做實參傳遞給另外一個函數
import time
def bar():
time.sleep(3)
print("in the bar")
def test1(func): ##根據test1(bar)的調用可以看出,這裏的func = bar。這就是把bar函數名傳遞給func當test1的實參
start_time=time.time()
func() #run bar()
stop_time=time.time()
print("the func run time is %s"%(stop_time-start_time))
test1(bar)
b:返回值中包含函數名
import time
def bar():
time.sleep(3)
print("in the bar")
def test2(func):
print(func)
return func #f返回bar的內存值
print(test2(bar))
t=test2(bar) #test2執行結果賦值給了t,相當於把bar(賦值給了t,當使用t()時,就是在執行bar函數
t() #run bar()
3.嵌套函數 (在一個函數體內用def聲明一個函數叫嵌套。調用不叫嵌套)
#局部即變量
def foo():
def bar():
print("in the bar")
bar() ##想要輸出print結果就需要一層層的調用
foo()
#局部作用和全局作用域的訪問順序
x=0
def boo():
def daa():
x=2
def son():
x=3
print(x)
son()
daa()
boo()
猜測下這裏的輸出結果是:
下面寫個簡單的裝飾器。(高階函數+嵌套函數=》裝飾器)
不設定函數實參
import time
def timer(func): ##func=test1=test2
def deco():
start_time=time.time()
func() ##func=test1 =test2
stop_time=time.time()
print("the funce run time is %s" %(stop_time-start_time))
return deco
def test1():
time.sleep(3)
print("in the test1")
@timer
def test2():
time.sleep(3)
print("in the test2")
test1=timer(test1)
test1() ##-->deco
test2()
當設定test實參時,可以這樣寫。deco() func()裏面都直接*args,***kwargs不限量。如果具體某一個參數,那就可以修改為具體的。
import time
def timer(func):
def deco(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs)
stop_time=time.time()
print("the funce run time is %s" %(stop_time-start_time))
return deco
def test1():
time.sleep(3)
print("in the test1")
@timer #非固定參數name
def test2(name):
time.sleep(3)
print("in the test2",name)
test1=timer(test1)
test1() ##-->deco
test2("alex")
模擬遠端登錄與本地登錄試驗:
user,passwd="alex","abc"
def auth(auth_type):
print("auth>>>",auth_type)
def outer_wrapper(func):
def wrapper(*args,**kwargs):
print("*args,**kwargs",*args,**kwargs)
if auth_type=="local":
username=input("Input user: ").strip()
password=input("Input password: ").strip()
if username==user and password==passwd:
print("\033[32;1mUser has passed authentication\033[0m")
res=func(*args,**kwargs)
return res
else:
exit("\033[31;1mIminvalid username or password\033[0m")
elif auth_type=="ldap":
print("不會")
return wrapper
return outer_wrapper
def index():
print("welcome to index page")
@auth(auth_type="local") ##本地驗證登錄
def home():
print("welcome to home page")
return "from home"
@auth(auth_type="ldap") ##遠端驗證登錄
def dds():
print("welcome to dds page")
index()
print(home())
dds()
【24】Python裝飾器筆記