從零到精通:Python 裝飾器的完整指南與實戰應用
作者:用戶007
本文將從基礎原理出發,逐步深入裝飾器的各種應用場景,幫助你真正掌握這項強大的工具。
裝飾器是Python中最優雅卻最容易被誤解的特性之一。許多初學者對"裝飾"這個概念感到困惑,高級開發者則可能陷入過度使用裝飾器的陷阱。本文將從基礎原理出發,逐步深入裝飾器的各種應用場景,幫助你真正掌握這項強大的工具。

一、裝飾器的本質原理
1. 什么是裝飾器
裝飾器本質上是一個函數,它接收另一個函數作為參數,并返回一個新函數。這個新函數通常會在原函數執行前后進行某些操作。
# 最簡單的裝飾器
defmy_decorator(func):
defwrapper():
print("執行前")
func()
print("執行后")
return wrapper
@my_decorator
defsay_hello():
print("Hello!")
# 等同于:say_hello = my_decorator(say_hello)
say_hello()
# 輸出:
# 執行前
# Hello!
# 執行后2. 保留原函數的元數據
使用裝飾器后,原函數的元數據(如函數名、文檔字符串)會丟失。使用functools.wraps可以解決這個問題。
from functools import wraps
defmy_decorator(func):
@wraps(func)
defwrapper(*args, **kwargs):
"""這是wrapper函數"""
print("執行前")
result = func(*args, **kwargs)
print("執行后")
return result
return wrapper
@my_decorator
defadd(a, b):
"""將兩個數相加"""
return a + b
print(add.__name__) # 'add',而不是'wrapper'
print(add.__doc__) # '將兩個數相加'二、裝飾器的常見應用場景
1. 性能監測裝飾器
import time
from functools import wraps
deftimeit(func):
@wraps(func)
defwrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 耗時:{end - start:.4f}秒")
return result
return wrapper
@timeit
defslow_function():
time.sleep(1)
return"完成"
result = slow_function()2. 日志記錄裝飾器
import logging
from functools import wraps
deflog_calls(level=logging.INFO):
defdecorator(func):
@wraps(func)
defwrapper(*args, **kwargs):
logging.log(level, f"調用 {func.__name__} 參數:{args}, {kwargs}")
result = func(*args, **kwargs)
logging.log(level, f"{func.__name__} 返回值:{result}")
return result
return wrapper
return decorator
@log_calls(level=logging.DEBUG)
defprocess_data(data):
return data.upper()
process_data("hello")3. 函數參數驗證裝飾器
from functools import wraps
defvalidate_types(**type_checks):
defdecorator(func):
@wraps(func)
defwrapper(*args, **kwargs):
for arg_name, expected_type in type_checks.items():
if arg_name in kwargs:
ifnot isinstance(kwargs[arg_name], expected_type):
raise TypeError(f"{arg_name} 必須是 {expected_type}")
return func(*args, **kwargs)
return wrapper
return decorator
@validate_types(name=str, age=int)
defcreate_user(name, age):
returnf"創建用戶:{name}, 年齡:{age}"
create_user(name="Alice", age=25) # 正常
# create_user(name="Alice", age="25") # 會拋出TypeError4. 緩存裝飾器(Memoization)
from functools import wraps, lru_cache
# 簡單的緩存實現
defcache(func):
cached_data = {}
@wraps(func)
defwrapper(*args):
if args notin cached_data:
cached_data[args] = func(*args)
return cached_data[args]
wrapper.cache = cached_data
return wrapper
@cache
deffibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 使用內置的lru_cache
@lru_cache(maxsize=128)
deffibonacci_builtin(n):
if n < 2:
return n
return fibonacci_builtin(n-1) + fibonacci_builtin(n-2)
print(fibonacci(30)) # 快速計算
print(fibonacci.cache) # 查看緩存5. 重試裝飾器
from functools import wraps
import time
import random
defretry(max_attempts=3, delay=1, backoff=2):
defdecorator(func):
@wraps(func)
defwrapper(*args, **kwargs):
current_delay = delay
last_exception = None
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
last_exception = e
if attempt < max_attempts - 1:
print(f"嘗試 {attempt + 1} 失敗,{current_delay}秒后重試...")
time.sleep(current_delay)
current_delay *= backoff
raise last_exception
return wrapper
return decorator
@retry(max_attempts=3, delay=1, backoff=2)
defunstable_api_call():
if random.random() < 0.7:
raise Exception("API調用失敗")
return"成功"
result = unstable_api_call()6. 權限驗證裝飾器
from functools import wraps
defrequire_permission(*required_perms):
defdecorator(func):
@wraps(func)
defwrapper(user, *args, **kwargs):
ifnot hasattr(user, 'permissions'):
raise PermissionError("用戶無權限屬性")
user_perms = set(user.permissions)
required = set(required_perms)
ifnot required.issubset(user_perms):
raise PermissionError(f"用戶缺少權限:{required - user_perms}")
return func(user, *args, **kwargs)
return wrapper
return decorator
classUser:
def__init__(self, name, permissions):
self.name = name
self.permissions = permissions
@require_permission('admin', 'delete')
defdelete_user(user, user_id):
returnf"{user.name} 刪除了用戶 {user_id}"
admin_user = User("Admin", ['admin', 'delete', 'read', 'write'])
delete_user(admin_user, 123) # 成功7. 速率限制裝飾器
from functools import wraps
import time
from collections import defaultdict
defrate_limit(calls_per_second=1):
min_interval = 1.0 / calls_per_second
last_called = [0.0]
defdecorator(func):
@wraps(func)
defwrapper(*args, **kwargs):
elapsed = time.time() - last_called[0]
if elapsed < min_interval:
time.sleep(min_interval - elapsed)
last_called[0] = time.time()
return func(*args, **kwargs)
return wrapper
return decorator
@rate_limit(calls_per_second=2)
defapi_call():
print(f"API調用時間:{time.time()}")
return"成功"
for _ in range(5):
api_call()8. 方法裝飾器和類裝飾器
from functools import wraps
# 方法裝飾器
defmethod_logger(func):
@wraps(func)
defwrapper(self, *args, **kwargs):
print(f"調用方法 {self.__class__.__name__}.{func.__name__}")
return func(self, *args, **kwargs)
return wrapper
# 類裝飾器
defadd_str_repr(cls):
def__str__(self):
attrs = ', '.join(f"{k}={v}"for k, v in self.__dict__.items())
returnf"{cls.__name__}({attrs})"
cls.__str__ = __str__
return cls
@add_str_repr
classPerson:
def__init__(self, name, age):
self.name = name
self.age = age
@method_logger
defgreet(self):
returnf"你好,我是{self.name}"
person = Person("Alice", 25)
print(person) # Person(name=Alice, age=25)
person.greet() # 調用方法 Person.greet三、高級裝飾器模式
9. 可選參數的裝飾器
from functools import wraps
defsmart_decorator(func=None, *, enabled=True):
defdecorator(f):
ifnot enabled:
return f
@wraps(f)
defwrapper(*args, **kwargs):
print("裝飾器生效")
return f(*args, **kwargs)
return wrapper
if func isNone:
# 被調用時帶參數:@smart_decorator(enabled=True)
return decorator
else:
# 被調用時不帶參數:@smart_decorator
return decorator(func)
@smart_decorator
deffunc1():
return"func1"
@smart_decorator(enabled=False)
deffunc2():
return"func2"10. 鏈式裝飾器
defdecorator_a(func):
@wraps(func)
defwrapper(*args, **kwargs):
print("A前")
result = func(*args, **kwargs)
print("A后")
return result
return wrapper
defdecorator_b(func):
@wraps(func)
defwrapper(*args, **kwargs):
print("B前")
result = func(*args, **kwargs)
print("B后")
return result
return wrapper
@decorator_a
@decorator_b
defmy_func():
print("執行函數")
return"結果"
my_func()
# 輸出:
# A前
# B前
# 執行函數
# B后
# A后四、結尾
裝飾器是Python中最強大的工具之一,也是代碼復用和關注點分離的最佳實踐。從簡單的日志記錄到復雜的權限驗證,裝飾器都能優雅地解決問題。然而,要記住裝飾器的目的是讓代碼更清晰、更易維護。過度使用裝飾器反而會增加代碼復雜性。
責任編輯:趙寧寧
來源:
Python數智工坊




































