0

0

Python 带参数装饰器的正确写法

舞姬之光

舞姬之光

发布时间:2026-01-29 17:46:02

|

701人浏览过

|

来源于php中文网

原创

带参数装饰器必须返回真正的装饰器函数,即三层嵌套结构:最外层接收参数并校验,中间层接收被装饰函数并返回内层函数,最内层执行逻辑且需用@functools.wraps(func)保留原函数元信息。

python 带参数装饰器的正确写法

带参数装饰器必须返回一个真正的装饰器函数

很多人写 @log(level="DEBUG") 时直接在最外层函数里写逻辑,结果报错 TypeError: 'NoneType' object is not callable。根本原因是:带参数的装饰器结构是三层函数,最外层接收参数,中间层接收被装饰的函数,最内层才是实际执行逻辑的闭包。

常见错误写法:def log(level): ... return wrapper()(多写了括号,直接调用了);或漏掉中间层,导致 Python 尝试用函数本身去装饰目标函数,而它又不是可调用对象。

  • 最外层:接收装饰器参数,比如 levelname
  • 中间层:接收被装饰的函数 func,必须返回内层函数
  • 最内层:接收 *args, **kwargs,负责调用原函数并添加逻辑

正确结构模板:三阶嵌套 + functools.wraps 不可省

不加 @functools.wraps(func),被装饰函数的 __name____doc__ 全变成内层函数的名字(比如 inner),对调试、文档生成、框架反射(如 FastAPI 路由注册)都会出问题。

from functools import wraps

def log(level="INFO"):
    def decorator(func):
        @wraps(func)
        def inner(*args, **kwargs):
            print(f"[{level}] Calling {func.__name__}")
            return func(*args, **kwargs)
        return inner
    return decorator

注意:@wraps(func) 必须作用于最内层函数(inner),且 func 是中间层传入的那个原始函数。

立即学习Python免费学习笔记(深入)”;

crmeb电商系统
crmeb电商系统

CRMEB 是基于Thinkphp5基础开发的以会员为中心的电商系统,开源版微信公众号商城和小程序商城数据同步,带积分、优惠券、秒杀、砍价、分销等功能,更是一套方便二次开发的商城框架(后台封装了独有快速创建表单功能,无需写表单页面、快速创建数据搜索和数据列表页、导出表格、系统权限配置控制每一个控制器方法、系统参数配置、数据字典、组合数据等)

下载

参数校验和默认值要在最外层处理

如果允许用户传非法 level(比如 @log(level="TRACE") 但日志系统不支持),应该在最外层就抛错,而不是等函数运行时才检查——否则每次调用都重复判断,浪费性能,也掩盖了配置错误。

  • 参数类型/范围检查放在最外层函数体中(def log(level=...): 后立即校验)
  • 避免在 inner 中做耗时初始化(如打开文件、连接数据库),应提至中间层或最外层完成
  • 若需动态参数(如从环境变量读取),可在最外层用 lambda 或闭包捕获,但要小心延迟求值陷阱

类实现的带参装饰器:更易维护但要注意 __call__ 签名

当逻辑变复杂(比如要缓存状态、支持重置、多参数组合),用类比嵌套函数更清晰。但必须确保类实例是可调用的,且中间层行为不被绕过。

class Log:
    def __init__(self, level="INFO"):
        self.level = level

    def __call__(self, func):
        @wraps(func)
        def inner(*args, **kwargs):
            print(f"[{self.level}] {func.__name__}")
            return func(*args, **kwargs)
        return inner

@Log(level="WARNING")
def foo(): pass

关键点:__call__ 方法就是中间层,它接收 func 并返回包装函数;类初始化只跑一次,适合带状态的装饰逻辑。但别忘了 @wraps 仍得用在 inner 上。

容易忽略的是:类装饰器无法像函数装饰器那样支持 @Log()@Log 两种写法同时存在——后者会把类本身当 func 传给 __call__,直接崩。统一要求带括号,能减少歧义。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python FastAPI异步API开发_Python怎么用FastAPI构建异步API
Python FastAPI异步API开发_Python怎么用FastAPI构建异步API

Python FastAPI 异步开发利用 async/await 关键字,通过定义异步视图函数、使用异步数据库库 (如 databases)、异步 HTTP 客户端 (如 httpx),并结合后台任务队列(如 Celery)和异步依赖项,实现高效的 I/O 密集型 API,显著提升吞吐量和响应速度,尤其适用于处理数据库查询、网络请求等耗时操作,无需阻塞主线程。

27

2025.12.22

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

207

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

191

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

55

2026.01.05

go语言闭包相关教程大全
go语言闭包相关教程大全

本专题整合了go语言闭包相关数据,阅读专题下面的文章了解更多相关内容。

137

2025.07.29

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

358

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2082

2023.08.14

vb怎么连接数据库
vb怎么连接数据库

在VB中,连接数据库通常使用ADO(ActiveX 数据对象)或 DAO(Data Access Objects)这两个技术来实现:1、引入ADO库;2、创建ADO连接对象;3、配置连接字符串;4、打开连接;5、执行SQL语句;6、处理查询结果;7、关闭连接即可。

349

2023.08.31

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

1

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

相关下载

更多

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 3.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号