Python3.5裝飾器原理及應(yīng)用實(shí)例詳解
本文實(shí)例講述了Python3.5裝飾器原理及應(yīng)用。分享給大家供大家參考,具體如下:
1、裝飾器:
(1)本質(zhì):裝飾器的本質(zhì)是函數(shù),其基本語(yǔ)法都是用關(guān)鍵字def去定義的。
(2)功能:裝飾其他函數(shù),即:為其他函數(shù)添加附加功能。
(3)原則:不能修改被裝飾的函數(shù)的源代碼,不能修改被裝飾的函數(shù)的調(diào)用方式。即:裝飾器對(duì)待被修飾的函數(shù)是完全透明的。
(4)簡(jiǎn)單應(yīng)用:統(tǒng)計(jì)函數(shù)運(yùn)行時(shí)間的裝飾器
import time
#統(tǒng)計(jì)函數(shù)運(yùn)行時(shí)間的磚裝飾器
def timmer(func):
def warpper(*args,**kwargs):
strat_time = time.time()
func()
stop_time = time.time()
print("the func run time is %s" %(stop_time-strat_time))
return warpper
@timmer
def test1():
time.sleep(3)
print("in the test1")
test1()
運(yùn)行結(jié)果:
in the test1
the func run time is 3.000171661376953
(5)實(shí)現(xiàn)裝飾器知識(shí)儲(chǔ)備:
a、函數(shù)即“變量”
b、高階函數(shù)
c、函數(shù)嵌套
d、高階函數(shù)+嵌套函數(shù)==》裝飾器
2、裝飾器知識(shí)儲(chǔ)備——函數(shù)即“變量”
定義一個(gè)函數(shù),相當(dāng)于把函數(shù)體賦值給這個(gè)函數(shù)名。
Python解釋器如何回收變量:采用引用計(jì)數(shù)。當(dāng)引用有沒(méi)有了時(shí)(門牌號(hào)不存在),變量就被回收了。
函數(shù)的定義也有內(nèi)存回收機(jī)制,與變量回收機(jī)制一樣。匿名函數(shù)沒(méi)有函數(shù)名,就會(huì)被回收。

變量的使用:先定義再調(diào)用,只要在調(diào)用之前已經(jīng)存在(定義)即可;函數(shù)即“變量”,函數(shù)的使用是一樣的。
函數(shù)調(diào)用順序:其他的高級(jí)語(yǔ)言類似,Python 不允許在函數(shù)未聲明之前,對(duì)其進(jìn)行引用或者調(diào)用
下面的兩段代碼運(yùn)行效果一樣:
def bar():
print("in the bar")
def foo():
print("in the foo")
bar()
foo()
#python為解釋執(zhí)行,函數(shù)foo在調(diào)用前已經(jīng)聲明了bar和foo,所以bar和foo無(wú)順序之分
def foo():
print("in the foo")
bar()
def bar():
print("in the bar")
foo()
運(yùn)行結(jié)果:
in the foo
in the bar
in the foo
in the bar
注意:python為解釋執(zhí)行,函數(shù)foo在調(diào)用前已經(jīng)聲明了bar和foo,所以bar和foo無(wú)順序之分
原理圖為:

3、裝飾器知識(shí)儲(chǔ)備——高階函數(shù)
滿足下列其中一種即可稱之為高階函數(shù):
a、把一個(gè)函數(shù)名當(dāng)做實(shí)參傳遞給另一個(gè)函數(shù)(在不修改被裝飾函數(shù)的情況下為其添加附加功能)
b、返回值中包含函數(shù)名(不修改函數(shù)的調(diào)用方式)
(1)高階函數(shù)示例:
def bar():
print("in the bar")
def test1(func):
print(func) #打印門牌號(hào),即內(nèi)存地址
func()
test1(bar) #門牌號(hào)func=bar
運(yùn)行結(jié)果:
<function bar at 0x00BCDFA8>
in the bar
(2)高階函數(shù)的妙處——把一個(gè)函數(shù)名當(dāng)做實(shí)參傳遞給另一個(gè)函數(shù)(在不修改被裝飾函數(shù)的情況下為其添加附加功能)
import time
def bar():
time.sleep(3)
print("in the bar")
#test2在不修改被修飾函數(shù)bar的代碼時(shí)添加了附加的及時(shí)功能
def test2(func):
start_time = time.time()
func() #run bar
stop_time = time.time()
print("the func run time is %s " %(stop_time-start_time))
#調(diào)用方式發(fā)生改變,不能像原來(lái)的方法去調(diào)用被修飾的函數(shù)(所以不能實(shí)現(xiàn)裝飾器的功能)
test2(bar)
#bar()
運(yùn)行結(jié)果:
in the bar
the func run time is 3.000171661376953
(3)高階函數(shù)的妙處——返回值中包含函數(shù)名(不修改函數(shù)的調(diào)用方式)
import time
def bar():
time.sleep(3)
print("in the bar")
def test3(func):
print(func)
return func
bar = test3(bar)
bar() #run bar
運(yùn)行結(jié)果:
<function bar at 0x00BADFA8>
in the bar
4、裝飾器知識(shí)儲(chǔ)備——嵌套函數(shù)
#函數(shù)嵌套
def foo():
print("in the foo")
def bar(): #bar函數(shù)具有局部變量的特性,不能在外部調(diào)用,只能在內(nèi)部調(diào)用
print("in the bar")
bar()
foo()
運(yùn)行結(jié)果:
in the foo
in the bar
裝飾器應(yīng)用——模擬網(wǎng)站登錄頁(yè)面,訪問(wèn)需要認(rèn)證登錄頁(yè)面
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
#模擬網(wǎng)站,訪問(wèn)頁(yè)面和部分需要登錄的頁(yè)面
import timer
user,passwd = "liu","liu123"
def auth(func):
def wrapper(*args,**kwargs):
username = input("Username:").strip()
password = input("Password:").strip()
if username == user and password == passwd:
print("\033[32;1mUser has passed authentication!\033[0m")
res = func(*args,**kwargs)
print("-----after authentication---")
return res
else:
exit("\033[31;1mInvalid username or password!\033[0m")
return wrapper
def index():
print("welcome to index page!")
@auth
def home():
print("welcome to index home!")
return "from home"
@auth
def bbs():
print("welcome to index bbs!")
#函數(shù)調(diào)用
index()
print(home())
bbs()
運(yùn)行結(jié)果:
welcome to index page!
Username:liu
Password:liu123
User has passed authentication!
welcome to home page!
-----after authentication---
from home
Username:liu
Password:liu123
User has passed authentication!
welcome to bbs page!
-----after authentication---
裝飾器帶參數(shù)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
#模擬網(wǎng)站,訪問(wèn)頁(yè)面和部分需要登錄的頁(yè)面,多種認(rèn)證方式
import timer
user,passwd = "liu","liu123"
def auth(auth_type):
print("auth func:",auth_type)
def outer_wrapper(func):
def wrapper(*args, **kwargs):
print("wrapper func args:",*args, **kwargs)
if auth_type == "local":
username = input("Username:").strip()
password = input("Password:").strip()
if username == user and password == passwd:
print("\033[32;1mUser has passed authentication!\033[0m")
#被裝飾的函數(shù)中有返回值,裝飾器中傳入的參數(shù)函數(shù)要有返回值
res = func(*args, **kwargs) #from home
print("-----after authentication---")
return res
else:
exit("\033[31;1mInvalid username or password!\033[0m")
elif auth_type == "ldap":
print("ldap....")
return wrapper
return outer_wrapper
def index():
print("welcome to index page!")
@auth(auth_type="local") #利用本地登錄 home = wrapper()
def home():
print("welcome to home page!")
return "from home"
@auth(auth_type="ldap") #利用遠(yuǎn)程的ldap登錄
def bbs():
print("welcome to bbs page!")
#函數(shù)調(diào)用
index()
print(home()) #wrapper()
bbs()
運(yùn)行結(jié)果:

更多關(guān)于Python相關(guān)內(nèi)容可查看本站專題:《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python Socket編程技巧總結(jié)》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》及《Python入門與進(jìn)階經(jīng)典教程》
希望本文所述對(duì)大家Python程序設(shè)計(jì)有所幫助。
相關(guān)文章
python flask框架實(shí)現(xiàn)傳數(shù)據(jù)到j(luò)s的方法分析
這篇文章主要介紹了python flask框架實(shí)現(xiàn)傳數(shù)據(jù)到j(luò)s的方法,結(jié)合實(shí)例形式分析了前端數(shù)據(jù)序列化及后臺(tái)Flask交互數(shù)據(jù)返回相關(guān)操作技巧,需要的朋友可以參考下2019-06-06
python使用xmlrpclib模塊實(shí)現(xiàn)對(duì)百度google的ping功能
這篇文章主要介紹了python使用xmlrpclib模塊實(shí)現(xiàn)對(duì)百度google的ping功能,實(shí)例分析了xmlrpclib模塊的相關(guān)技巧,需要的朋友可以參考下2015-06-06
Python 解決logging功能使用過(guò)程中遇到的一個(gè)問(wèn)題
這篇文章主要介紹了Python 解決logging功能使用過(guò)程中遇到的一個(gè)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04
python爬蟲 使用真實(shí)瀏覽器打開網(wǎng)頁(yè)的兩種方法總結(jié)
下面小編就為大家分享一篇python爬蟲 使用真實(shí)瀏覽器打開網(wǎng)頁(yè)的兩種方法總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-04-04
Python模擬登錄驗(yàn)證碼(代碼簡(jiǎn)單)
這篇文章主要介紹了Python模擬登錄驗(yàn)證碼(代碼簡(jiǎn)單)的相關(guān)資料,需要的朋友可以參考下2016-02-02

