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í)
在介紹類裝飾器之前,我們先簡(jiǎn)單回顧一下函數(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è)新類。
最簡(jiǎn)單的類裝飾器可以這樣定義:
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() # 拋出 PermissionError3.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") # 拋出 ValueError4. 綜合示例
接下來,我們將通過一個(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+Appium實(shí)現(xiàn)自動(dòng)搶微信紅包
不知從何時(shí)開始微信紅包橫空出世,對(duì)于網(wǎng)速和手速慢的人只能在一旁觀望,做為python的學(xué)習(xí)者就是要運(yùn)用編程解決生活和工作上的事情。于是我用python解決我們的手速問題python實(shí)現(xiàn)自動(dòng)搶微信紅包,至于網(wǎng)速慢得那就只能自己花錢提升了。2021-05-05
Python模塊已安裝但導(dǎo)入時(shí)報(bào)錯(cuò)的完美解決
在Python編程中,有時(shí)即使你已經(jīng)使用pip或conda等工具安裝了某個(gè)包,但在嘗試導(dǎo)入時(shí)仍可能遇到錯(cuò)誤,這篇文章主要介紹了Python模塊已安裝但導(dǎo)入時(shí)報(bào)錯(cuò)的完美解決辦法,需要的朋友可以參考下2025-11-11
關(guān)于CUDA out of memory的解決方案
這篇文章主要介紹了關(guān)于CUDA out of memory的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02
Python + Requests庫(kù)爬取動(dòng)態(tài)Ajax分頁(yè)數(shù)據(jù)的完整流程
本文介紹使用Python+Requests庫(kù)爬取動(dòng)態(tài)Ajax分頁(yè)數(shù)據(jù)的完整流程,包含請(qǐng)求分析、參數(shù)模擬、翻頁(yè)邏輯實(shí)現(xiàn)、JSON解析及數(shù)據(jù)存儲(chǔ),同時(shí)提供反爬優(yōu)化策略,適用于電商、新聞等動(dòng)態(tài)加載內(nèi)容的網(wǎng)站,感興趣的朋友一起看看吧2025-07-07

