当前位置: 首页 > news >正文

Python中的装饰器

93d8c196be7f30dbaee98dc6aa527946.png

迷途小书童的 Note

读完需要

5

分钟

速读仅需 2 分钟

装饰器是一个非常有用而又常被误解的功能,可以让我们在不修改函数或类的源代码情况下给它们提供扩展功能。本文将通过具体示例带你深入理解 Python 装饰器的用法。

1

   

装饰器基础

装饰器本质上是一个函数,它可以让其他函数在不需要做任何代码变动的前提下添加额外功能。装饰器的语法如下

@decorator 
def func():pass

这里的 @decorator 就表示使用 decorator 这个装饰器来装饰后面的函数。

我们来看一个具体的例子

from functools import wrapsdef log(func):@wraps(func)  def wrapper(*args, **kwargs):print(f"Call {func.__name__}")return func(*args, **kwargs)return wrapper@log
def add(x, y):return x + yprint(add(2, 3))

执行上述代码,输出结果为

Call add
5

这里我们定义了一个名为 log 装饰器,它会打印函数名称然后再调用原函数。通过 @log 就可以来装饰 add 函数,使其获得打印日志的功能。

2

   

带参数的装饰器

装饰器本身也可以带参数,需要多一层封装

from functools import wrapsdef repeat(num):def decorator(func):@wraps(func)def wrapper(*args, **kwargs):for _ in range(num):func(*args, **kwargs)return wrapperreturn decorator@repeat(num=3)
def greet(name):print(f"Hello {name}")greet("xgx")

执行上述脚本,输出结果为

Hello xgx
Hello xgx  
Hello xgx

这种带参数的装饰器在一些特殊场景下非常有用,如需要自定义执行的次数。

3

   

装饰类

装饰器不仅可以装饰函数,还可以装饰类,看下面的示例

from functools import wrapsclass CountCalls:def __init__(self, func):self.func = funcself.num_calls = 0def __call__(self, *args, **kwargs):self.num_calls += 1print(f"Call {self.num_calls} of {self.func.__name__!r}")return self.func(*args, **kwargs)@CountCalls
def say_hello(name):print(f"Hello {name}")say_hello("xgx")
say_hello("Alice")

执行上述脚本,输出结果为

Call 1 of 'say_hello'
Hello xgx
Call 2 of 'say_hello'
Hello Alice

这里我们定义了一个 CountCalls 类,实现了 __init__() 和 __call__() 方法。使用 @CountCalls 装饰 say_hello 函数时,会先创建 CountCalls 实例对象,并将 say_hello 函数存入实例的 func 属性。在调用 say_hello 时,实际上调用的是 CountCalls 实例对象,它会更新调用次数,打印信息,最后再调用原始的 say_hello 函数。这样就实现了一个统计调用次数的装饰器。

类装饰器的好处是可以存储状态,方便扩展额外的功能。

4

   

多个装饰器

多个装饰器可以层层嵌套,执行顺序由里到外。

@decorator1
@decorator2
def func():pass

例如

@repeat(num=3) 
@log
def greet(name):print(f"Hello {name}")

greet 函数先由 @log 装饰,然后由 @repeat 装饰。

所以装饰器的顺序会影响函数的行为。

5

   

总结

装饰器是一个非常强大和有用的功能,可以让我们在不修改源代码的情况下动态扩展函数和类的功能,是每个 Python 程序员都应该掌握的重要知识点。

6

   

免费社群

bbef8b29cb147b6850cdf73fdf66c9e7.jpeg

http://www.lryc.cn/news/156237.html

相关文章:

  • 什么是RESTful API,Spring MVC如何支持RESTful架构
  • cin、cin.getline()、getline()的用法【C++】
  • 单向链表(c/c++)
  • 像linux 一样清理Windows C盘
  • 在Linux 下制作启动盘以及dd命令使用
  • C语言插入排序
  • SQL-DCL
  • Elasticsearch 中的向量搜索:设计背后的基本原理
  • Jquery会议室布局含门入口和投影位置调整,并自动截图
  • 高精度乘法模板(fft)
  • C# 现状简单说明
  • el-table滚动加载、懒加载(自定义指令)
  • 不关闭Tamper Protection(篡改保护)下强制卸载Windows Defender和安全中心所有组件
  • 从一到无穷大 #13 How does Lindorm TSDB solve the high cardinality problem?
  • 三维模型OBJ格式轻量化的纹理压缩和质量关系分析
  • 【每日一题】54. 螺旋矩阵
  • git:一些撤销操作
  • leetcode 209. 长度最小的子数组
  • 《rk3399:各显示接口的dts配置》
  • Python数据分析-Pandas
  • golang 多线程管理 -- chatGpt
  • 【Math】导数、梯度、雅可比矩阵、黑塞矩阵
  • 【C语言】——调试技巧
  • 【Python】pytorch,CUDA是否可用,查看显卡显存剩余容量
  • React16入门到入土
  • 【GPT引领前沿】GPT4技术与AI绘图
  • 【LeetCode】19. 删除链表的倒数第 N 个结点
  • spring boot3.x集成swagger出现Type javax.servlet.http.HttpServletRequest not present
  • 《低代码指南》——智能化低代码开发实践案例
  • 268_C++_字节计算(((bits) + 7) / 8)、字节对齐(((number) + 3) / 4 * 4)