【后端】【python】利用反射器----动态设置装饰器

📘 Python 装饰器进阶指南


一、装饰器本质

✅ 本质概念

Python 装饰器的本质是 函数嵌套 + 返回函数,它是对已有函数的增强,不修改原函数代码,使用语法糖 @decorator 实现包裹效果。

def my_decorator(func):def wrapper(*args, **kwargs):print("Before")result = func(*args, **kwargs)print("After")return resultreturn wrapper@my_decorator
def say_hello():print("Hello!")

✅ 装饰器其实是这样的调用:

say_hello = my_decorator(say_hello)

二、元数据保持:functools.wraps

❗ 问题

普通装饰器会丢失原函数的元数据,如 __name__, __doc__ 等。

✅ 解决方案:使用 functools.wraps

from functools import wrapsdef my_decorator(func):@wraps(func)def wrapper(*args, **kwargs):print("Running:", func.__name__)return func(*args, **kwargs)return wrapper

🌟 好处

  • 文档自动生成工具能识别原始函数
  • 保持调试友好、函数签名保留

三、反射 + 动态设置装饰器

✅ 场景:你不想在函数上一个个手动写 @装饰器,而是运行时自动批量装饰。

示例:动态为某类中所有特定方法添加装饰器

def my_log_decorator(func):@wraps(func)def wrapper(*args, **kwargs):print(f"[LOG] {func.__name__} 被调用")return func(*args, **kwargs)return wrapperclass MyClass:def method_a(self): print("A")def method_b(self): print("B")# 动态装饰
for name in ['method_a', 'method_b']:method = getattr(MyClass, name)setattr(MyClass, name, my_log_decorator(method))obj = MyClass()
obj.method_a()

四、进阶实践:Django DRF + 动态文档装饰器

✅ 背景

使用 drf-spectacular 时,需要为 ViewSet 方法添加 @extend_schema,但方法多、内容重复,适合动态处理。

💡 做法:定义映射 + 动态应用装饰器

from drf_spectacular.utils import extend_schema
from functools import wraps
from rest_framework import viewsetsclass SchemaModelViewSet(viewsets.ModelViewSet):schema_summary_mapping = {'list': "获取{name}列表",'retrieve': "获取单个{name}",'create': "创建{name}",'update': "更新{name}",'partial_update': "局部更新{name}",'destroy': "删除{name}"}# 动态应用装饰器
def _apply_schema_decorators():for method_name, summary_tpl in SchemaModelViewSet.schema_summary_mapping.items():if hasattr(SchemaModelViewSet, method_name):base_method = getattr(viewsets.ModelViewSet, method_name)@wraps(base_method)def dynamic_wrapper(*args, **kwargs):return base_method(*args, **kwargs)decorated = extend_schema(summary=summary_tpl.format(name="对象"))(dynamic_wrapper)setattr(SchemaModelViewSet, method_name, decorated)_apply_schema_decorators()

✅ 优点

  • 方法不需要手动一个个写装饰器
  • 支持格式化 summary,按模型/资源名称自动生成
  • 保持方法原始签名与元数据,文档准确生成

五、进阶技巧汇总

技巧说明
@wraps(func)保持元数据,推荐用于所有自定义装饰器
动态装饰使用 getattr + setattr 为方法动态添加装饰器
装饰器工厂装饰器接收参数时需要多层函数嵌套
多重装饰多个装饰器可层层嵌套处理逻辑
类装饰器__call__ 方法定义类装饰器

六、结语

装饰器是 Python 函数式编程的核心工具,掌握以下几点,就可以自由应对开发中的各种装饰器需求:

  • 理解函数对象 & 嵌套函数原理
  • 使用 wraps 保持元信息
  • 动态反射结合装饰器进行自动化增强
  • 在大型框架(如 Django DRF)中实现文档或权限的自动化控制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79273.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nodejs Express框架

参考:Node.js Express 框架 | 菜鸟教程 第一个 Express 框架实例 接下来我们使用 Express 框架来输出 "Hello World"。 以下实例中我们引入了 express 模块,并在客户端发起请求后,响应 "Hello World" 字符串。 创建 e…

Docker Swarm 集群

Docker Swarm 集群 本文档介绍了 Docker Swarm 集群的基本概念、工作原理以及相关命令使用示例,包括如何在服务调度中使用自定义标签。本文档适用于需要管理和扩展 Docker 容器化应用程序的生产环境场景。 1. 什么是 Docker Swarm Docker Swarm 是用于管理 Docker…

充电宝项目中的MQTT(轻量高效的物联网通信协议)

文章目录 补充:HTTP协议MQTT协议MQTT的核心特性MQTT vs HTTP:关键对比 EMQX项目集成EMQX集成配置客户端和回调方法具体接口和方法处理处理类 补充:HTTP协议 HTTP是一种应用层协议,使用TCP作为传输层协议,默认端口是80…

【iOS】UIPageViewController学习

UIPageViewController学习 前言创建一个UIPageViewController最简单的使用 UIPageViewController的方法说明:效果展示 UIPageViewController的协议方法 前言 笔者最近在写项目时想实现一个翻书效果,上网学习到了UIPageViewController今天写本篇博客总结…

Linux搭建环境:从零开始掌握基础操作(四)

​ ​ 您好,我是程序员小羊! 前言 软件测试第一步就是搭建测试环境,如何搭建好测试环境,需要具备两项的基础知识: 1、Linux 命令: 软件测试第一个任务, 一般都需要进行环境搭建, 一部分,环境搭建内容是在服…

一天一个java知识点----Tomcat与Servlet

认识BS架构 静态资源:服务器上存储的不会改变的数据,通常不会根据用户的请求而变化。比如:HTML、CSS、JS、图片、视频等(负责页面展示) 动态资源:服务器端根据用户请求和其他数据动态生成的,内容可能会在每次请求时都…

YOLOV8 OBB 海思3516训练流程

YOLOV8 OBB 海思3516训练流程 目录 1、 下载带GPU版本的torch(可选) 1 2、 安装 ultralytics 2 3、 下载pycharm 社区版 2 4、安装pycharm 3 5、新建pycharm 工程 3 6、 添加conda 环境 4 7、 训练代码 5 9、配置Ymal 文件 6 10、修改网络结构 9 11、运行train.py 开始训练模…

【深度学习】花书第18章——配分函数

直面配分函数 许多概率模型(通常是无向图模型)由一个未归一化的概率分布 p ~ ( x , θ ) \tilde p(\mathbf x,\theta) p~​(x,θ)定义。我们必须通过除以配分函数 Z ( θ ) Z(\pmb{ \theta}) Z(θ)来归一化 p ~ \tilde p p~​。以获得一个有效的概率分…

工作记录1

日常总结、灵感记录、学习要点。持续记录 学海无涯,再好的记性也比不过烂笔头,记录一下学习日常、灵感、要点。 前言:最近看见一个博文,很有感触,是某个大佬自己运营的网站,分享了他的各种经验文章和自身的一些笔记。本人还没有他这么屌,所以还是先在CSDN上小试牛刀吧…

Spring Boot(二十一):RedisTemplate的String和Hash类型操作

RedisTemplate和StringRedisTemplate的系列文章详见: Spring Boot(十七):集成和使用Redis Spring Boot(十八):RedisTemplate和StringRedisTemplate Spring Boot(十九)…

智能指针之设计模式1

本文探讨一下智能指针和GOF设计模式的关系,如果按照设计模式的背后思想来分析,可以发现围绕智能指针的设计和实现有设计模式的一些思想体现。当然,它们也不是严格意义上面向对象的设计模式,毕竟它们没有那么分明的类层次体系&…

中间件--ClickHouse-1--基础介绍(列式存储,MPP架构,分布式计算,SQL支持,向量化执行,亿万级数据秒级查询)

1、概述 ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。它由俄罗斯的互联网巨头Yandex为解决其内部数据分析需求而开发,并于2016年开源。专为大规模数据分析,实时数据分析和复杂查询设计,具有高性能、实时数据和可扩展性等…

Go之Slice和数组:深入理解底层设计与最佳实践

在Go语言中,数组(Array)和切片(Slice)是两种看似相似却本质不同的数据结构。本文将深入剖析它们的底层实现机制,并结合实际代码示例,帮助开发者掌握核心差异和使用场景。 一、基础概念&#xff…

力扣热题100——普通数组(不普通)

普通数组但一点不普通! 最大子数组和合并区间轮转数组除自身以外数组的乘积缺失的第一个正数 最大子数组和 这道题是非常经典的适用动态规划解决题目,但同时这里给出两种解法 动态规划、分治法 那么动态规划方法大家可以在我的另外一篇博客总结中看到&am…

矩阵基础+矩阵转置+矩阵乘法+行列式与逆矩阵

GPU渲染过程 矩阵 什么是矩阵(Matrix) 向量 (3,9,88) 点乘:计算向量夹角 叉乘:计算两个向量构成平面的法向量。 矩阵 矩阵有3行,2列,所以表示为M32 获取固…

MySQL之text字段详细分类说明

在 MySQL 中,TEXT 是用来存储大量文本数据的数据类型。TEXT 类型可以存储非常长的字符串,比 VARCHAR 类型更适合存储大块的文本数据。TEXT 数据类型分为以下几个子类型,每个子类型用于存储不同大小范围的文本数据: TINYTEXT: 可以…

超详细!Android 面试题大汇总与深度解析

一、Java 与 Kotlin 基础 1. Java 的多态是如何实现的? 多态是指在 Java 中,同一个行为具有多个不同表现形式或形态的能力。它主要通过方法重载(Overloading)和方法重写(Overriding)来实现。 方法重载&a…

如何提高webrtc操作跟手时间,降低延迟

第一次做webrtc项目,操作延迟,一直是个问题,多次调试都不能达到理想效果。偶尔发现提高jitterBuffer时间可以解决此问题。关键代码 const _setJitter (values: number) > { const receives peerConnection.getReceivers();receives.f…

语音合成(TTS)从零搭建一个完整的TTS系统-第一节-效果演示

一、概述 语音合成又叫文字转语音(TTS-text to speech ),本专题我们记录从零搭建一个完整的语音合成系统,包括文本前端、声学模型和声码器,从模型训练到系统的工程化实现,模型可以部署在手机等嵌入式设备上…

实验三 I/O地址译码

一、实验目的 掌握I/O地址译码电路的工作原理。 二、实验电路 实验电路如图1所示,其中74LS74为D触发器,可直接使用实验台上数字电路实验区的D触发器,74LS138为地址译码器, Y0:280H~287H&…