如何在类中实现类似Flask route的装饰器并正确传递self
类内装饰器模仿Flask route时的self传递问题
场景与初始错误
想要模仿Flask的app.route()装饰器用法,实现类内的实例方法装饰器,但遇到self传递和参数解析错误。初始代码如下:
class A: def __init__(self): pass def very_important_function(self, text): # 处理逻辑 def decorator(self, func, text): def inner(): if not self.very_important_function(text): return "Fail!" func() return inner a = A() @a.decorator("text") def check(): return True check()
运行后报错:
A.decorator.<locals>.inner() takes 0 positional arguments but 1 was given
尝试functools.wraps后的新问题
添加functools.wraps()装饰inner后:
def decorator(self, func, text): @functools.wraps(func) def inner(): if not self.very_important_function(text): return "Fail!" func() return inner
出现新错误:
A.decorator() missing 1 required positional argument: 'text'
本质是@a.decorator("text")的调用逻辑被错误解析:Python将"text"当作func参数传入,导致缺少text参数。
核心需求与疑问
希望完全模仿app.route()的使用方式:用户无需手动传递实例参数,装饰器必须作为类的实例方法存在(类似app.route()通过实例调用)。想了解如何将类内装饰器绑定到实例,以及正确访问绑定对象的方法。
后续装饰器工厂尝试与错误
尝试实现AuthenticationManager类中的login_required装饰器工厂,但仍报错:
# 完整AuthenticationManager类代码略,仅展示login_required方法 def login_required(self, func, uauth_response: flask.Response = None, groups: list[str] = None): def decorator(func): def inner(*args, **kwargs): if not self.uauth_response or not uauth_response: uauth_response = flask.Response( "You are not authorised to access this resource.", status=401 ) if not uauth_response and self.uauth_response: uauth_response = self.uauth_response if not self.check_auth(): return uauth_response if groups: user_groups = self.get_groups() for group in groups: if group not in user_groups: return uauth_response func(*args, **kwargs) return inner return decorator
报错信息:
TypeError: AuthenticationManager.login_required() missing 1 required positional argument: 'func'
原因是Python将被装饰的函数当作self之后的第一个参数传入,而方法定义中func是必填参数,导致参数不匹配。
解决方案
问题的核心是装饰器的嵌套层级错误:Flask的route()是一个装饰器工厂——先接收路由参数,返回一个真正的装饰器函数去接收被装饰的视图函数。类内实例方法装饰器需要遵循同样的结构:
1. 修正基础示例的装饰器结构
import functools class A: def __init__(self): pass def very_important_function(self, text): # 示例处理逻辑,返回True模拟验证通过 return True def decorator(self, text): # 第一层:接收装饰器参数(text),返回真正的装饰器 def actual_decorator(func): # 第二层:接收被装饰的函数func @functools.wraps(func) def inner(*args, **kwargs): # 第三层:执行装饰逻辑,保留原函数的参数传递 if not self.very_important_function(text): return "Fail!" return func(*args, **kwargs) return inner return actual_decorator a = A() @a.decorator("text") def check(): return True print(check()) # 输出:True
2. 修正AuthenticationManager的login_required方法
from functools import wraps # 其他方法保持不变,仅修改login_required def login_required(self, uauth_response: flask.Response = None, groups: list[str] = None): def decorator(func): @wraps(func) def inner(*args, **kwargs): # 统一处理响应对象 auth_response = uauth_response or self.uauth_response if not auth_response: auth_response = flask.Response( "You are not authorised to access this resource.", status=401 ) # 验证逻辑 if not self.check_auth(): return auth_response if groups: user_groups = self.get_groups() # 检查用户是否拥有所需权限组 if not user_groups or any(group not in user_groups for group in groups): return auth_response # 执行原函数并返回结果 return func(*args, **kwargs) return inner return decorator
关键说明
- 实例方法装饰器需要三层嵌套:第一层接收装饰器的配置参数(如text、groups),第二层接收被装饰的函数,第三层是实际执行装饰逻辑的包装函数。
- 使用
functools.wraps(func)可以保留原函数的元信息(如函数名、文档字符串),避免后续调试或框架依赖时出现问题。 - 包装函数
inner需要传递*args, **kwargs给原函数,并返回原函数的执行结果,确保被装饰函数的行为符合预期。
内容的提问来源于stack exchange,提问作者sawntoe
相关产品推荐
相关产品推荐

