Python自定义装饰器

article/2025/8/27 20:28:35

文章目录

    • 1.闭包
    • 2.不带参数的装饰器
    • 3.带参数的装饰器
    • 4.不定长参数的装饰器
    • 5.多重装饰器修饰
    • 6.返回值是装饰器
    • 7.装饰器类


Python学习笔记—装饰器

装饰器:从生活角度理解,是对一个东西进行装饰,增加它本身的一些功能和内容;
Python中的装饰器,也大致可以这样理解,它本质上就是扩展原本函数功能的一种函数。它是通过函数闭包进行实现的。

1.闭包

闭包是什么?
答: 定义在一个函数中的函数称为闭包函数,前一个函数称为外函数,后一个函数称为内函数,闭包指的就是,内函数总是可以访问其所在的外函数中声明的参数和变量,即使在其外函数被返回之后。

想要实现闭包,需要三个条件:

  • 函数嵌套,即存在内函数和外函数
  • 内函数使用了外函数的变量或者参数
  • 外函数需要return内函数

举例:

def func_out():  # 外函数num1 = 10def func_in(num2):   # 内函数t = num1 + num2print("%d + %d = %d"%(num1,num2,t))return func_in  # 返回内函数, 不加括号# 这里实际上是 func_out()函数调用之后返回的内函数地址赋值给f
f = func_out()   
f(1)   # 为了方便记忆,可以直接将内函数与这里的f直接等价,调用的时候,需要以内函数的形参列表为基准传入参数
# 输出: 10 + 1 =11

思考:有没有想过,写在代码中的函数名到底是什么呢?
答: 其实是函数体代码的存储地址。

举例:

def test():pass
print(test)    # 输出 :<function test at 0x000001AC070275E0>
  • 这个时候,在回头看一下闭包的例子,外函数返回的是内函数的地址,f接收的是外函数调用的结束后返回的内函数地址,这时想要调用内函数,直接按照内函数的形参列表给f传入参数即可。
  • 在深入一点,一般情况下,在func_out()函数调用结束后,它内部的num1局部变量理应被销毁释放,但是f在调用时候,还是用到了num1的值,这就是闭包的真正含义。

2.不带参数的装饰器

装饰器就是通过闭包实现的,接下来举两个常见例子帮助理解:
  • 日志打印器 – 通知函数执行和结束
def decorate(func):     # 这里的参数是函数print("装饰器执行了")      # 可以看出,这里的装饰器就是外函数有了参数的闭包def inner():print("执行函数了")func()print("函数执行结束了")return inner;@decorate      # @decorate 值得是装饰器语法糖,它的执行意义是 comment = decorate(comment)  comment()
def comment():print("评论开始了")comment()

@ 符号就是装饰器的语法糖。它放在一个函数开始定义的地方,它就像一顶帽子一样戴在这个函数的头上,和这个函数绑定在一起。在我们调用这个函数的时候,第一件事并不是执行这个函数,而是将这个函数做为参数传入它头顶上这顶帽子,这顶帽子我们称之为装饰函数 或 装饰器。

  • 函数时间计时器 --计算一个函数执行的时间
from time import *     # 导入time模块,具体导入模块可以参看我的另一篇文章def decorate(func):  # 外函数,这里的func参数为@下一行的函数def inner():    # 内函数begin = time()func()            # 这里调用了外函数的局部变量end = time()result = end - begin   print("执行的时间为:"+str(result))return inner;@decorate     # 装饰器语法糖
def work():s = 0for i in range(1,10001):s += iprint("1到10000的和为%d:"%(s))work()

以上两个例子就是不带参数的装饰器,在写装饰器的时候要注意装饰器内函数中调用func的形式,有时候func(@下一行 的函数)是有return返回值的,需要注意一下。

3.带参数的装饰器

  • 带参数的装饰器,指的是装饰器内部inner函数是需要有参数,也表明@装饰器修饰的函数也是需要有和inner函数有相同的形参列表。

举例:

def decorate (func):def inner(a,b):     # 这里的inner函数有参数,则也需要func也需要有参数print("努力计算中!!!")func(a,b)return inner@decorate  # 这里本质是 f = decorate(add1), f(a,b) 所以inner函数也需要和add1函数有相同的形参列表
def add1(a,b):    print("%d + %d = %d"%(a,b,a+b))add1(2,3)
# 输出: 努力计算中!!!
# 2 + 3 = 5

建议 想要加深理解,一定要参考上面提到的函数名本质是函数本体代码存放的地址,就是一段地址值。将注释后的代码用地址代入走一遍,就更容易理解了

4.不定长参数的装饰器

有了上面的带参数的装饰器,这里的不定长参数的装饰器,就是将inner函数的参数列表改为不定长参数占位符就可以了。具体可以参考我的另外一篇文章《Python函数中的不定长参数》

举例:

def decorate(func):def inner(*args,**kwargs):     # 不定长参数列表print("不定长装饰器运行啦")func(*args,**kwargs)      # 内函数调用外函数变量return inner     # 返回内函数@decorate  # 相当于 f = decorate(add_num),  f(*args,**kwargs)
def add_num(*args,**kwargs):s = 0for i in args:s += ifor i in kwargs.values():s += iprint("和为:", s)add_num(1,2,3,4)

结果演示:
在这里插入图片描述

5.多重装饰器修饰

  • 即一个函数有多个装饰器修饰。

举例:

def make_div(func):print("make_div 装饰器");def inne():result = '<div>' + func() + '</div>'return resultreturn inne;def make_p(func):print("make_p 装饰器");def inne():result = '<p>' + func() + '</p>'return resultreturn inne;@make_div    # 当一个函数有多个装饰器时候,谁靠的近先执行谁,
@make_p   # 本质上调用的是 f = make_p(content) f1 = make_div(f) 
def content():return "人生苦短,我用python"print(content())

运行结果:
在这里插入图片描述

  • 主要掌握的是在多重装饰器修饰函数时,装饰器运行的先后顺序:谁距离被修饰的函数就先用谁修饰

6.返回值是装饰器

按照要求,则返回的是装饰器,则return decorate。

举例:

def return_decorate(flag):   # 定义一个函数用来返回装饰器def decorate(func):def inner(a,b):if flag == '+':print("执行的是加法运算")func(a,b)elif flag == '-':print("执行的是减法运算")func(a,b)return inner;return decorate@return_decorate('+')  # 实际上执行的是 f = return_decorate('+') f1 = f(add_num) f1(a,b)
def add_num(a,b):print("%d + %d = %d"%(a,b,a+b))@return_decorate('-')
def sub_num(a,b):print("%d - %d = %d"%(a,b,a-b))add_num(2,4)
sub_num(4,2)

结果演示:
在这里插入图片描述

7.装饰器类

将装饰器函数封装成类,通过__call__函数将类转化为可调用的对象,用对象调用被修饰的函数

举例:

class MyDecorate(object):def __init__(self,func):   # 这里相当于将func初始化为类的实例属性,相当于外函数的局部变量self.func = funcdef __call__(self, *args, **kwargs):     # 该方法将类变为可调用的对象,可调用的对象能够和函数一样调用使用,这里相当于对inner内函数的相关执行代码进行规范化处理print("装饰器类调用了")self.func(*args,*kwargs)@MyDecorate    # f = MyDecorate(show),f(str)
def show(str):print(str)@MyDecorate
def add(a,b):print("%d + %d = %d"%(a,b,a+b))show("加油,奥里给")
add(3,5)

结果展示:
在这里插入图片描述

这里的装饰器类,可以大大的增加的代码的通用性,同时需要注意,当类中出现__call__魔法方法时,该类大概率为装饰器类。


http://chatgpt.dhexx.cn/article/BHNxk0qO.shtml

相关文章

Python的装饰器

前言&#xff1a; &#x1f921; 作者简介&#xff1a;我是Morning&#xff0c;计算机的打工人&#xff0c;想要翻身做主人 &#x1f648; &#x1f648; &#x1f648; &#x1f3e0; 个人主页&#xff1a;Morning的主页 &#x1f4d5;系列专栏&#xff1a;&#…

装 饰 器

一&#xff0c;装饰器概念 装饰器本质上还是函数&#xff0c;让其它的函数在不做任何代码修改的情况下&#xff0c;增加额外的功能 所以说一句话&#xff1a;还是函数&#xff0c;记住奥 谈到一个原则&#xff1a;开发封闭原则 概念&#xff1a; 一个以函数作为参数并返回一…

学习TypeScript20(装饰器Decorator)

Decorator 装饰器是一项实验性特性&#xff0c;在未来的版本中可能会发生改变 它们不仅增加了代码的可读性&#xff0c;清晰地表达了意图&#xff0c;而且提供一种方便的手段&#xff0c;增加或修改类的功能 若要启用实验性的装饰器特性&#xff0c;你必须在命令行或tsconfig…

python装饰器详解

python中的装饰器(decorator)一般采用语法糖的形式&#xff0c;是一种语法格式。比如&#xff1a;classmethod&#xff0c;staticmethod&#xff0c;property&#xff0c;xxx.setter&#xff0c;wraps()&#xff0c;func_name等都是python中的装饰器。 装饰器&#xff0c;装饰的…

【Python】一文弄懂python装饰器(附源码例子)

目录 前言 一、什么是装饰器 二、为什么要用装饰器 三、简单的装饰器 四、装饰器的语法糖 五、装饰器传参 六、带参数的装饰器 七、类装饰器 八、带参数的类装饰器 九、装饰器的顺序 总结 写在后面 前言 最近有人问我装饰器是什么&#xff0c;我就跟他说&#xff…

偏微分方程数值解程序设计与实现——数学基础

常用算子符号 梯度算子 R d \mathbb{R}^d Rd空间中标量函数 u ( x ) u(\bf{x}) u(x)&#xff0c;其梯度算子定义如下&#xff1a; g r a d u ( x ) ∇ u ( x ) [ ∂ u ∂ x 0 ∂ u ∂ x 1 ⋮ ∂ u ∂ x d − 1 ] grad u(\mathbf{x})\nabla u(\mathbf{x}) \begin{bmatrix} …

偏微分方程的数值解(六): 偏微分方程的 pdetool 解法

偏微分方程的数值解系列博文&#xff1a; 偏微分方程的数值解(一):定解问题 & 差分解法 偏微分方程的数值解(二): 一维状态空间的偏微分方程的 MATLAB 解法 偏微分方程的数值解(三): 化工应用实例 ----------触煤反应装置内温度及转换率的分布 偏微分方程的数值解(四):…

微分方程数值解

一阶问题举例&#xff1a; 高阶问题举例 &#xff1a; 常微分方程数值解&#xff1a;向前欧拉方法之一阶问题 clc,clear,close all; a0;%初始时刻 b2*pi;%结束时刻 n100;%离散点数量 x00;%初值 h(b-a)/n;%步长 xx0 [0:n]*h;%离散点数组 funinline(sin(x)y,x,y); y01; %计算 y(…

常微分方程数值解法1

&#xff11;.牛顿迭代法 多数方程不存在求根公式&#xff0c;因此求精确根非常困难&#xff0c;甚至不可能&#xff0c;从而寻找方程的近似根就显得特别重要。牛顿迭代法使用函数 的泰勒级数的前面几项来寻找方程 的根。牛顿迭代法是求方程根的重要方法之一&#xff0c;其最大…

差分、偏微分方程的解法

这里写目录标题 微分方程数值求解——有限差分法matlab代码差分法的运用&#xff08;依旧是连续变量——>离散网格点&#xff09; PDE求解思路demo1demo2 微分方程数值求解——有限差分法 差分方法又称为有限差分方法或网格法&#xff0c;是求偏微分方程定解问题的数值解中…

微分方程数值解法(2)——椭圆型方程的有限差分法

此处参考教材为李荣华的《微分方程数值解法》 使用工具&#xff1a;Matlab 1. 算法&#xff1a;矩形网格上5点差分格式 2. 算法 I.需要求解的函数 function [v,vx,vy,f,aa,bb,cc,dd]u2D(x,y,ft)% ft为方程编号&#xff0c;u1D为精确解函数u&#xff08;t&#xff09;,注意与…

基础数学(8)——常微分方程数值解法

文章目录 期末考核方式基础知识解析解&#xff08;公式法&#xff09;解析解例题&#xff08;使用公式法&#xff0c;必考&#xff09;解析解的局限性 数值解数值解的基本流程 显示Euler法显示欧拉&#xff08;差值理解&#xff09;显示欧拉&#xff08;Taylor展开理解&#xf…

微分方程数值解法(1)——常微分方程初值问题的数值解法

此处参考教材为李荣华的《微分方程数值解法》 使用工具&#xff1a;Matlab 1. 算法 注: 最后一行应为k4,上面为笔误 2. 算法 I.需要求解的函数 function ff1D(t,u,ft)% ft为方程编号&#xff0c;u1D为精确解函数u(t),注意与f1D对应右端项函数f(t,u(t))switch ftcase 1 %P10…

偏微分方程数值解法pdf_天生一对,硬核微分方程与深度学习的联姻之路

机器之心原创 作者&#xff1a;蒋思源 微分方程真的能结合深度神经网络&#xff1f;真的能用来理解深度神经网络、推导神经网络架构、构建深度生成模型&#xff1f;本文将从鄂维南、董彬和陈天琦等研究者的工作中&#xff0c;窥探微分方程与深度学习联袂前行的路径。 近日&…

椭圆型偏微分方程数值解法

一、 一维椭圆方程数值解 matlab代码&#xff1a; function chap2_fdm_elliptic_1D % 一维椭圆方程求解(常微分方程边值问题) % -u q(x)u f(x), 0<x<1, 取q(x) x, f(x) (x-1)exp(x) % u(0) 1, u(1) e; 边界条件 % 真解为 u exp(x)N 20; h 1/N; x_al…

Python小白的数学建模课-11.偏微分方程数值解法

偏微分方程可以描述各种自然和工程现象&#xff0c; 是构建科学、工程学和其他领域的数学模型主要手段。 偏微分方程主要有三类&#xff1a;椭圆方程&#xff0c;抛物方程和双曲方程。 本文采用有限差分法求解偏微分方程&#xff0c;通过案例讲解一维平流方程、一维热传导方程…

偏微分方程数值解法pdf_单摆-微分方程浅谈

引子[1] 单摆&#xff0c;这个在中学物理都学过的东西&#xff0c;应该是非常熟悉了。 图片来源-维基百科 小角度简单摆 若最高处( )的绳子和最低处(速度最大值)的绳子的角度为 &#xff0c;则可使用下列公式算出它的振动周期。 公式证明 摆球受力分析 绳与对称线夹角为 &…

偏微分方程数值解法pdf_数值模拟偏微分方程的三种方法:FDM、FEM及FVM

偏微分方程数值模拟常用的方法主要有三种:有限差分方法(FDM)、有限元方法(FEM)、有限体积方法(FVM),本文将对这三种方法进行简单的介绍和比较。 一.有限差分方法 有限差分方法(Finite Difference Methods)是数值模拟偏微分方程最早采用的方法,至今仍被广泛运用。该方法包括区…

正圆锥体空间方程_数值模拟偏微分方程的三种方法:FDM、FEM及FVM

偏微分方程数值模拟常用的方法主要有三种:有限差分方法(FDM)、有限元方法(FEM)、有限体积方法(FVM),本文将对这三种方法进行简单的介绍和比较。 一.有限差分方法 有限差分方法(Finite Difference Methods)是数值模拟偏微分方程最早采用的方法,至今仍被广泛运用。该方法包括区…

抖音图标

抖音图标&#xff1a; 1.创建一张画布&#xff0c;再用圆角矩形工具创建一个圆角矩形 2.新建一个图层&#xff0c;用椭圆选框工具创建一个圆&#xff0c;再alt键从选区减去一个圆 3.再填充一个颜色&#xff0c;再剪切1/4圆接着粘贴拖拽至右上方 4.新建一个图层&#xff0c;用…