Python全景系列之裝飾器使用的全面講解
Python 裝飾器深入探討
在 Python 中,裝飾器提供了一種簡(jiǎn)潔的方式,用來(lái)修改或增強(qiáng)函數(shù)和類的行為。裝飾器在語(yǔ)法上表現(xiàn)為一個(gè)前置于函數(shù)或類定義之前的特殊標(biāo)記:
@simple_decorator def hello_world(): print("Hello, world!")
在這個(gè)例子中,simple_decorator
是一個(gè)裝飾器,它作用于下方的 hello_world
函數(shù)。裝飾器在概念上就像一個(gè)包裝器,它可以在被裝飾的函數(shù)執(zhí)行前后插入任意的代碼,進(jìn)而改變被裝飾函數(shù)的行為。
參數(shù)化裝飾器
我們還可以進(jìn)一步將裝飾器參數(shù)化,這讓裝飾器的行為更具靈活性。比如,我們可以定義一個(gè)裝飾器,讓它在函數(shù)執(zhí)行前后打印自定義的消息:
def message_decorator(before_message, after_message): def decorator(func): def wrapper(*args, **kwargs): print(before_message) result = func(*args, **kwargs) print(after_message) return result return wrapper return decorator @message_decorator("Start", "End") def hello_world(): print("Hello, world!")
在這個(gè)例子中,message_decorator
是一個(gè)參數(shù)化裝飾器,它接受兩個(gè)參數(shù),分別代表函數(shù)執(zhí)行前后要打印的消息。
理解裝飾器的工作原理
在 Python 中,函數(shù)是第一類對(duì)象。這意味著函數(shù)和其他對(duì)象一樣,可以作為變量進(jìn)行賦值,可以作為參數(shù)傳給其他函數(shù),可以作為其他函數(shù)的返回值,甚至可以在一個(gè)函數(shù)里面定義另一個(gè)函數(shù)。這個(gè)特性是實(shí)現(xiàn)裝飾器的基礎(chǔ)。
def decorator(func): def wrapper(): print('Before function execution') func() print('After function execution') return wrapper def hello_world(): print('Hello, world!') decorated_hello = decorator(hello_world) decorated_hello()
在這個(gè)例子中,decorator
函數(shù)接收一個(gè)函數(shù) hello_world
作為參數(shù),并返回了一個(gè)新的函數(shù) wrapped_func
。這個(gè)新函數(shù)在 hello_world
函數(shù)執(zhí)行前后分別打印一條消息。我們可以看到,裝飾器實(shí)際上是一個(gè)返回函數(shù)的函數(shù)。
函數(shù)簽名保持
默認(rèn)情況下,裝飾器會(huì)“掩蓋”掉原函數(shù)的名字和文檔字符串。這是因?yàn)樵谘b飾器內(nèi)部,我們返回了一個(gè)全新的函數(shù)。我們可以使用 functools.wraps
來(lái)解決這個(gè)問(wèn)題:
import functools def decorator(func): @functools.wraps(func) def wrapper(): print('Before function execution') func() print('After function execution') return wrapper @decorator def hello_world(): "Prints 'Hello, world!'" print('Hello, world!') print(hello_world.__name__) print(hello_world.__doc__)
這樣,使用裝飾器后的函數(shù)名和文檔字符串能夠保持不變。
Python 裝飾器的應(yīng)用實(shí)例
裝飾器在實(shí)際的 Python 編程中有許多應(yīng)用場(chǎng)景,比如日志記錄、性能測(cè)試、事務(wù)處理、緩存、權(quán)限校驗(yàn)等。
一個(gè)常見的應(yīng)用就是使用裝飾器進(jìn)行日志記錄:
import logging def log_decorator(func): logging.basicConfig(level=logging.INFO) def wrapper(*args, **kwargs): logging.info(f'Running "{func.__name__}" with arguments {args} and kwargs {kwargs}') result = func(*args, **kwargs) logging.info(f'Finished "{func.__name__}" with result {result}') return result return wrapper @log_decorator def add(x, y): return x + y
這個(gè)裝飾器記錄了函數(shù)的名稱,函數(shù)調(diào)用的參數(shù),以及函數(shù)返回的結(jié)果。
裝飾器鏈
Python 允許我們將多個(gè)裝飾器應(yīng)用到一個(gè)函數(shù)上,形成一個(gè)裝飾器鏈。例如,我們可以同時(shí)應(yīng)用日志裝飾器和性能測(cè)試裝飾器:
import time import logging from functools import wraps def log_decorator(func): logging.basicConfig(level=logging.INFO) @wraps(func) def wrapper(*args, **kwargs): logging.info(f'Running "{func.__name__}" with arguments {args} and kwargs {kwargs}') result = func(*args, **kwargs) logging.info(f'Finished "{func.__name__}" with result {result}') return result return wrapper def timer_decorator(func): @wraps(func) def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f'Function "{func.__name__}" took {end_time - start_time} seconds to run.') return result return wrapper @log_decorator @timer_decorator def add(x, y): time.sleep(2) return x + y
在這個(gè)例子中,@log_decorator
和 @timer_decorator
兩個(gè)裝飾器被同時(shí)應(yīng)用到 add
函數(shù)上,它們分別負(fù)責(zé)記錄日志和測(cè)量函數(shù)運(yùn)行時(shí)間。
One More Thing: 自動(dòng)注冊(cè)裝飾器
一個(gè)有趣的裝飾器應(yīng)用是自動(dòng)注冊(cè)。這個(gè)裝飾器會(huì)在裝飾函數(shù)時(shí)自動(dòng)將函數(shù)添加到一個(gè)列表或字典中,這樣我們就可以在程序的其他地方訪問(wèn)到這個(gè)列表或字典,知道有哪些函數(shù)被裝飾過(guò)。
# 裝飾器將函數(shù)注冊(cè)到一個(gè)列表中 def register_decorator(func_list): def decorator(func): func_list.append(func) return func return decorator # 自動(dòng)注冊(cè)函數(shù) registered_functions = [] @register_decorator(registered_functions) def foo(): pass @register_decorator(registered_functions) def bar(): pass print(registered_functions) # 輸出: [<function foo at 0x10d38d160>, <function bar at 0x10d38d1f0>]
這個(gè)裝飾器可以用于自動(dòng)注冊(cè)路由、插件系統(tǒng)、命令行參數(shù)處理等場(chǎng)景,能夠大大提高代碼的靈活性和可擴(kuò)展性。
總結(jié)
Python 裝飾器是一種強(qiáng)大的工具,它可以讓我們更有效地管理和組織代碼。希望通過(guò)這篇文章,你能夠更深入地理解裝飾器的工作原理和用法,從而在你的項(xiàng)目中更好地使用裝飾器。
到此這篇關(guān)于Python全景系列之裝飾器使用的全面講解的文章就介紹到這了,更多相關(guān)Python裝飾器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python神經(jīng)網(wǎng)絡(luò)Keras?GhostNet模型的實(shí)現(xiàn)
這篇文章主要為大家介紹了python神經(jīng)網(wǎng)絡(luò)Keras?GhostNet模型的復(fù)現(xiàn)詳解,2022-05-05Python檢查 云備份進(jìn)程是否正常運(yùn)行代碼實(shí)例
這篇文章主要介紹了Python檢查 云備份進(jìn)程是否正常運(yùn)行代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08vscode配置與python虛擬環(huán)境切換的幾種方式總結(jié)
Python之所以強(qiáng)大,除了語(yǔ)言本身的特性外,更重要的是擁有無(wú)所不及的第三方庫(kù),下面這篇文章主要給大家介紹了關(guān)于vscode配置與python虛擬環(huán)境切換的幾種方式,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12python 實(shí)現(xiàn)tar文件壓縮解壓的實(shí)例詳解
這篇文章主要介紹了python 實(shí)現(xiàn)tar文件壓縮解壓的實(shí)例詳解的相關(guān)資料,這里提供實(shí)現(xiàn)方法,幫助大家學(xué)習(xí)理解這部分內(nèi)容,需要的朋友可以參考下2017-08-08Python Scrapy多頁(yè)數(shù)據(jù)爬取實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了Python Scrapy多頁(yè)數(shù)據(jù)爬取實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06