方法怎么当装饰器用?看完这篇你就懂了 🚀
大家平时用装饰器,基本都是定义普通函数。其实,类里面定义的方法也能当装饰器用!今天就来聊聊这个骚操作,顺便看看它一般在哪些场景下会派上用场。
先来一个最简单的例子 🌰
class DecoratorClass:
def my_decorator(self, func):
def wrapper(*args, **kwargs):
print(f"Before calling {func.__name__}")
result = func(*args, **kwargs)
print(f"After calling {func.__name__}")
return result
return wrapper
# 注意:得先创建类的实例
decorator_instance = DecoratorClass()
@decorator_instance.my_decorator
def say_hello():
print("Hello!")
say_hello()
运行结果:
Before calling say_hello
Hello!
After calling say_hello
✅ 关键点:这里用的是 实例方法 作为装饰器,所以必须先 new 一个对象出来。
⚠️ 有几个坑需要提前知道
1️⃣ 实例方法必须绑定实例
不能直接写 @DecoratorClass.my_decorator,因为那样会把 self 搞丢。必须像下面这样:
class Logger:
def log(self, func):
def wrapper(*args, **kwargs):
print(f"Logging: {func.__name__} called")
return func(*args, **kwargs)
return wrapper
logger = Logger() # 👈 先创建实例
@logger.log # 👈 用实例的方法来装饰
def my_function():
pass
2️⃣ 类方法(classmethod)和静态方法(staticmethod)也可以
class Decorators:
@classmethod
def class_decorator(cls, func):
def wrapper(*args, **kwargs):
print(f"Class decorator from {cls.__name__}")
return func(*args, **kwargs)
return wrapper
@staticmethod
def static_decorator(func):
def wrapper(*args, **kwargs):
print("Static decorator")
return func(*args, **kwargs)
return wrapper
@Decorators.class_decorator # 直接通过类名调用
def func1():
pass
@Decorators.static_decorator
def func2():
pass
3️⃣ 装饰类内部的方法(self 怎么传?)
如果装饰器要用来装饰 同一个类里的其他方法,那就要小心处理 self:
class Validator:
def validate_positive(self, func):
def wrapper(instance, value): # 👈 instance 就是被装饰方法的 self
if value < 0:
raise ValueError("Value must be positive")
return func(instance, value)
return wrapper
class BankAccount:
def __init__(self):
self.balance = 0
@Validator().validate_positive # 👈 还是得先有实例
def deposit(self, amount):
self.balance += amount
return self.balance
account = BankAccount()
account.deposit(100) # 正常
# account.deposit(-50) # 会抛出 ValueError
💡 一般用在哪些场景?
🔁 注册模式(Registry Pattern)
class EventHandler:
def __init__(self):
self.handlers = {}
def on(self, event_name):
def decorator(func):
self.handlers[event_name] = func
return func
return decorator
handler = EventHandler()
@handler.on("click")
def handle_click():
print("Clicked!")
@handler.on("hover")
def handle_hover():
print("Hovering!")
这种写法在事件系统、插件注册、回调管理里非常常见。
🧠 总结一下
| 类型 | 能否当装饰器 | 注意事项 |
|---|---|---|
| 实例方法 | ✅ 能 | 需要先创建实例 |
| 类方法 | ✅ 能 | 直接用类名调用 |
| 静态方法 | ✅ 能 | 直接用类名调用 |
优点:
- 实例方法可以访问
self,因此可以做成有状态的装饰器(比如记录调用次数、保存配置等)。 - 适合做注册中心、校验器、日志记录、依赖注入等。
缺点(或者说需要注意的地方):
- 大部分情况下,你必须在装饰之前就拿到类的实例。
- 这意味着装饰器的配置是在运行时发生的,而不是在类定义时就固定下来。
总之,类方法作为装饰器是一种高级但很有用的技巧,掌握了它,你的代码会更优雅、更灵活。如果你用过 Flask 的路由装饰器,其实原理也差不多~ 😎

588

被折叠的 条评论
为什么被折叠?



