You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在类中实现类似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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 00:12:05