Python裝飾器之類裝飾器詳解
1. 引言
在Python中,裝飾器是一種允許我們?cè)诓桓淖冊(cè)写a的情況下,動(dòng)態(tài)地增加或修改函數(shù)和類功能的工具。
類裝飾器相較于函數(shù)裝飾器,功能更為強(qiáng)大和靈活,因?yàn)樗鼈儾粌H可以修飾類的方法,還可以修飾類本身。
2. 裝飾器的基本概念
裝飾器是一個(gè)接受函數(shù)或類并返回一個(gè)新函數(shù)或新類的高階函數(shù)。它們通常通過 @
符號(hào)來使用。
在使用裝飾器時(shí),我們將裝飾器放在被裝飾對(duì)象的上方,這樣裝飾器就會(huì)在對(duì)象創(chuàng)建時(shí)自動(dòng)應(yīng)用。
2.1. 函數(shù)裝飾器復(fù)習(xí)
在介紹類裝飾器之前,我們先簡單回顧一下函數(shù)裝飾器的基本用法。
def my_decorator(func): def wrapper(*args, **kwargs): print("Something is happening before the function is called.") result = func(*args, **kwargs) print("Something is happening after the function is called.") return result return wrapper @my_decorator def say_hello(name): print(f"Hello, {name}!") say_hello("Alice")
運(yùn)行上述代碼,輸出結(jié)果為:
Something is happening before the function is called.
Hello, Alice!
Something is happening after the function is called.
2.2 類裝飾器的定義和使用
類裝飾器與函數(shù)裝飾器類似,只不過它們接受一個(gè)類作為參數(shù),并返回一個(gè)新類。
最簡單的類裝飾器可以這樣定義:
def class_decorator(cls): class WrappedClass(cls): def new_method(self): print("This is a new method added by the decorator.") def existing_method(self): print("This method is overridden by the decorator.") return WrappedClass @class_decorator class MyClass: def existing_method(self): print("This method exists in the original class.") obj = MyClass() obj.new_method() # 調(diào)用新增的方法 obj.existing_method() # 調(diào)用被重寫的方法
運(yùn)行上述代碼,輸出結(jié)果為:
This is a new method added by the decorator.
This method is overridden by the decorator.
在這個(gè)例子中,class_decorator
是一個(gè)類裝飾器,它接受一個(gè)類 MyClass
作為參數(shù),并返回一個(gè)新的類 WrappedClass
。WrappedClass
繼承自 MyClass
,并新增和重寫了一些方法。
3. 類裝飾器的應(yīng)用場(chǎng)景
類裝飾器在實(shí)際開發(fā)中有很多應(yīng)用場(chǎng)景,下面是幾個(gè)常見的例子:
3.1. 自動(dòng)添加屬性
類裝飾器可以用來自動(dòng)為類添加一些屬性。
例如,我們可以創(chuàng)建一個(gè)裝飾器,自動(dòng)為類添加一個(gè) created_at
屬性,記錄對(duì)象的創(chuàng)建時(shí)間。
import datetime def add_timestamp(cls): class WrappedClass(cls): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.created_at = datetime.datetime.now() return WrappedClass @add_timestamp class MyClass: def __init__(self, name): self.name = name obj = MyClass("Alice") print(obj.name) # 輸出: Alice print(obj.created_at) # 輸出: 對(duì)象的創(chuàng)建時(shí)間
3.2 訪問控制
類裝飾器可以用來控制類的方法訪問權(quán)限。
例如,我們可以創(chuàng)建一個(gè)裝飾器,要求調(diào)用某些方法時(shí)必須有管理員權(quán)限。
def require_admin(cls): class WrappedClass(cls): def admin_method(self, *args, **kwargs): if not self.is_admin: raise PermissionError("Admin privileges required") return super().admin_method(*args, **kwargs) return WrappedClass @require_admin class MyClass: def __init__(self, is_admin): self.is_admin = is_admin def admin_method(self): print("This is an admin method.") admin_obj = MyClass(is_admin=True) admin_obj.admin_method() # 正常調(diào)用 user_obj = MyClass(is_admin=False) user_obj.admin_method() # 拋出 PermissionError
3.3 數(shù)據(jù)驗(yàn)證
類裝飾器可以用來在類方法調(diào)用前進(jìn)行數(shù)據(jù)驗(yàn)證。
例如,我們可以創(chuàng)建一個(gè)裝飾器,驗(yàn)證方法參數(shù)的類型。
def validate_params(cls): class WrappedClass(cls): def method_with_validation(self, x): if not isinstance(x, int): raise ValueError("Parameter x must be an integer") return super().method_with_validation(x) return WrappedClass @validate_params class MyClass: def method_with_validation(self, x): print(f"Received {x}") obj = MyClass() obj.method_with_validation(10) # 正常調(diào)用 obj.method_with_validation("a") # 拋出 ValueError
4. 綜合示例
接下來,我們將通過一個(gè)綜合示例來展示如何使用類裝飾器。
這個(gè)示例將包含一個(gè)日志記錄裝飾器、一個(gè)權(quán)限檢查裝飾器和一個(gè)數(shù)據(jù)驗(yàn)證裝飾器。
import datetime def log_activity(cls): class WrappedClass(cls): def __getattribute__(self, name): attr = super().__getattribute__(name) if callable(attr): def logged(*args, **kwargs): print(f"Calling {name} with arguments {args} and {kwargs} at {datetime.datetime.now()}") result = attr(*args, **kwargs) print(f"{name} returned {result}") return result return logged return attr return WrappedClass def require_permission(permission): def decorator(cls): class WrappedClass(cls): def __getattribute__(self, name): attr = super().__getattribute__(name) if callable(attr): def secured(*args, **kwargs): if not self.has_permission(permission): raise PermissionError(f"Permission {permission} required") return attr(*args, **kwargs) return secured return attr return WrappedClass return decorator def validate_params(cls): class WrappedClass(cls): def method_with_validation(self, x): if not isinstance(x, int): raise ValueError("Parameter x must be an integer") return super().method_with_validation(x) return WrappedClass @log_activity @require_permission("admin") @validate_params class MyClass: def __init__(self, is_admin): self.is_admin = is_admin def has_permission(self, permission): return self.is_admin def method_with_validation(self, x): return f"Received {x}" # 測(cè)試綜合示例 admin_obj = MyClass(is_admin=True) print(admin_obj.method_with_validation(10)) # 正常調(diào)用 try: admin_obj.method_with_validation("a") # 拋出 ValueError except ValueError as e: print(e) user_obj = MyClass(is_admin=False) try: user_obj.method_with_validation(10) # 拋出 PermissionError except PermissionError as e: print(e)
4.1 輸出結(jié)果
Calling __init__ with arguments (True,) and {} at 2024-07-11 14:23:45.123456
__init__ returned None
Calling method_with_validation with arguments (10,) and {} at 2024-07-11 14:23:45.123456
method_with_validation returned Received 10
Received 10
Calling method_with_validation with arguments ('a',) and {} at 2024-07-11 14:23:45.123456
Parameter x must be an integer
Calling __init__ with arguments (False,) and {} at 2024-07-11 14:23:45.123456
__init__ returned None
Calling method_with_validation with arguments (10,) and {} at 2024-07-11 14:23:45.123456
Permission admin required
4.2 解釋
- 日志記錄裝飾器:記錄類的方法調(diào)用,包括輸入?yún)?shù)和返回值。
- 權(quán)限檢查裝飾器:檢查用戶是否具有調(diào)用方法的權(quán)限。
- 數(shù)據(jù)驗(yàn)證裝飾器:驗(yàn)證方法參數(shù)的類型。
通過這種方式,我們可以在不修改類本身的情況下,為類添加額外的功能。
總結(jié)
類裝飾器是 Python 中一個(gè)非常強(qiáng)大的工具,可以用來擴(kuò)展和修改類的行為。通過類裝飾器,我們可以在不修改原始代碼的情況下為類添加額外的功能。
在實(shí)際開發(fā)中,類裝飾器有很多應(yīng)用場(chǎng)景,包括日志記錄、訪問控制、數(shù)據(jù)驗(yàn)證等。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Python實(shí)現(xiàn)學(xué)生管理系統(tǒng)的代碼(JSON模塊)
這篇文章主要介紹了Python實(shí)現(xiàn)學(xué)生管理系統(tǒng)的代碼(JSON模塊),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04Pygame實(shí)戰(zhàn)練習(xí)之飛機(jī)大戰(zhàn)游戲
飛機(jī)大戰(zhàn)想必是很多人童年時(shí)期的經(jīng)典游戲,我們依舊能記得抱個(gè)老人機(jī)娛樂的場(chǎng)景,下面這篇文章主要給大家介紹了關(guān)于如何利用python寫一個(gè)簡單的飛機(jī)大戰(zhàn)小游戲的相關(guān)資料,需要的朋友可以參考下2021-09-09Python數(shù)據(jù)庫封裝實(shí)現(xiàn)代碼示例解析
這篇文章主要介紹了Python數(shù)據(jù)庫封裝實(shí)現(xiàn)代碼示例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09python公司內(nèi)項(xiàng)目對(duì)接釘釘審批流程的實(shí)現(xiàn)
最近把組內(nèi)的一個(gè)項(xiàng)目對(duì)接釘釘審批接口,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08Python+Tkinter實(shí)現(xiàn)股票K線圖的繪制
K線圖又稱蠟燭圖,常用說法是“K線”。K線是以每個(gè)分析周期的開盤價(jià)、最高價(jià)、最低價(jià)和收盤價(jià)繪制而成。本文將利用Python+Tkinter實(shí)現(xiàn)股票K線圖的繪制,需要的可以參考一下2022-08-08在Django的URLconf中使用多個(gè)視圖前綴的方法
這篇文章主要介紹了在Django的URLconf中使用多個(gè)視圖前綴的方法,Django是Python中最為著名的遵循MVC結(jié)構(gòu)的開發(fā)框架,需要的朋友可以參考下2015-07-07