浅谈python中@装饰器 - 附例子(含类装饰器与函数装饰器)

news2024/11/16 3:47:14

浅谈python中@装饰器

文章目录

  • 浅谈python中@装饰器
    • 关于装饰器(decorator)
      • 小总结
    • 关于@(语法糖)
    • 进阶
      • 装饰器顺序
      • 装饰器 & 参数
    • End

提到@的使用首先要先讲一下装饰器的概念

关于装饰器(decorator)

先来看看官方文档上面是怎么写的:

A decorator is the name used for a software design pattern. Decorators
dynamically alter the functionality of a function, method, or class
without having to directly use subclasses or change the source code of
the function being decorated.
“装饰器是用于软件设计模式的名称。 装饰器可以动态更改功能,方法或类的功能,而不必直接使用子类或更改要修饰的功能的源代码。”(源自谷歌翻译)

而在python中装饰器是对python语法的特定更改,能更方便的修改函数和方法。通俗的说,装饰器相当于在不修改原有函数的基础上在其上增加别的功能。比如说我想每次使用函数的时候都打印一条日志作为标记,但是我又不想直接修改函数,这时装饰器就有用啦。装饰顾名思义是锦上添花的意思,在这个例子里“花”就是日志喽,大概是这样。

def triple_sum(a,b,c):
    print( "the sum is ",(a+b+c))
    
#log修饰器
def log_dec(func):
    def inner(a,b,c):
        print("logloglog")
        return func(a,b,c)
    return inner

new_fun=log_dec(triple_sum)
new_fun(1,2,3)

输出为
输出

这里还有个隐含的前置知识点,在python里,函数可以作为变量进行传递。

def triple_sum(a, b, c):
    print( "the sum is ",(a+b+c))

new_func = triple_sum
new_func(123, 234, 345)
print(new_func.__name__)

在这里插入图片描述

除了函数之外,类也可以作为装饰器进行包装

class Cube(object):
    def __init__(self, args):
        self.args = args

    def __call__(self, x, y):
        res = self.args(x, y)
        return res * res * res
# 这里Cube作为一个三次方的包装器,包装了一个普通的乘法函数
# 这里的乘法函数我用一个lambda表达式来略缩了
mul_nums = Cube(lambda x, y: x * y)
# 不使用lambda函数的话就是
#def mul_nums(x, y):
#    return x * y
#mul_nums = Cube(mul_nums)

print(mul_nums)
print(mul_nums(4, 3))

小总结

所以装饰器是什么,其实只是给当前的模块增加的新功能。装饰器可以是类,也可以是函数。它不会改变原来的函数本身,符合设计方法的开闭原则。

关于@(语法糖)

@ 实际上是python的语法糖,使用@对上面的两个例子进行改造
示例1:

def log_dec(func):
    print("logloglog")
    func(1,2,3)

@log_dec
def triple_sum(a,b,c):
    print( "the sum is ",(a+b+c))

结果输出为:
在这里插入图片描述
公式化一下@这个语法糖就是

@装饰器名 替代掉了 装饰器名(被装饰的函数)

即 triple_sum = log_dec(triple_sum)

示例2

@Cube
def mul_nums(x, y):
    return x * y

同理,@Cube替掉了mul_nums = Cube(mul_nums)

进阶

装饰器顺序

需要注意的是,想在已有函数上加的功能,需要在@之前声明(代码块的先后顺序)。同时,一个函数可以同时加几个装饰器。

从最下面的一个@函数开始运行,其下的函数作为他的输入。用print会看的更清楚一点

def log1(func):
    print("log1log1log1")

def log2(func):
    print("log2log2log2")
    func(1, 2, 3)

@log1
@log2
def triple_sum(a, b, c):
    print("the sum is ", (a + b + c))

输出为:
在这里插入图片描述
实际的运行相当于
triple_sum = log2(triple_sum)
triple_sum = log1(triple_sum)

装饰器 & 参数

1. 传参

可能有些盲生看到这里已经发现了华点,咋给triple_sum传参啊!(上面例子里面的值全都是写死的)这里我们就要对装饰器进行改造了。

在改造之前,需要知道一个前置知识,python中可以进行函数的嵌套,如

def func1():
    print("I'm in func1")
    def func2(msg):
        print("I'm in func2")
        print("I'm saying ",msg)
    func2("hello")

func1()

在这里插入图片描述
清楚了函数嵌套,再来看怎么改造装饰器参数

def log1(func):
    def wrapper(*args):
        print("logloglog")
        func(*args)
    return wrapper

@log1
def triple_sum(a, b, c):
    print("the sum is ", (a + b + c))

triple_sum(100,200,300)

在这里插入图片描述
使用函数嵌套就完成了装饰器的传参

2. 带参装饰器

此外,装饰器本身也可以携带参数。依然使用函数嵌套,再来一层。

def log_with_args(arg1,arg2):
    def log1(func):
        def wrapper(*args):
            print("logloglog")
            func(*args)
            print("arg1 is ",arg1,", args2 is ", arg2)
        return wrapper
    return log1

@log_with_args("hello","world")
def triple_sum(a, b, c):
    print("the sum is ", (a + b + c))

triple_sum(111,222,333)

在这里插入图片描述

End

以上即为装饰器的全部内容,欢迎评论区沟通指正。

参考

  1. 菜鸟教程 Python 函数装饰器
  2. 一大佬的文章,讲得很清楚

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

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

相关文章

计算机相关专业提升学历的解决方案(硕士研究生)

文章目录1、正规全日制硕士1.1 研究生入学考试1.2 硕士毕业要求2、继续教育(非全日制)2.1 在职研究生2.2 同等学力申硕3、海外硕士3.1 海外硕士申请3.2 中外合作项目1、正规全日制硕士 1.1 研究生入学考试 1、考试报名 官方网站:国家研究生…

玩转PPT 第2节 PPT第一辅助神器iSlide操作

ppt神器 第2节 islide常用操作锦集1 一键优化1.1 统一字体1.2 统一段落1.3 统一参考线1.4 统一主题色2 设计排版2.1 快速复制图形实现矩阵布局2.2 环形布局复制2.3 环形裁剪2.4 矩阵裁剪3 设计工具3.1 对齐3.2 大小3.3 对齐到参考线3.4 选择,相当于快速组合取消等3.…

树与二叉树深度剖析(二)

一. 树表示法1.双亲表示法(1).含义在一棵树中,任意一个结点的双亲只有一个,这是由树的定义决定的。双亲表示法就是利用了树的这个性质,在存储结点信息的同时,在每个节点中附设一个指向其双亲的指针, 指向双亲在链表中的…

IMX Linux 用户手册 — 3

IMX Linux 用户手册 — 3 10.3 CAAM Job Ring后端驱动规范 CAAM作业环后端驱动(caam_jr)实现并使用作业环接口(JRI)向CAAM引擎提交来自前端驱动(caamalg, caamhash, caampkc, caamrng, caamkeyblob)的加密API服务请求。 CAAM驱动程序有几个选项,最显著的是硬件工作…

ssm宿舍水电费报修考勤管理系统的开发与实现

目 录 摘 要 I 目 录 1 第1章 概述 1 1.1 研究背景 1 1.2 研究现状 1 1.3 研究内容 2 第二章 开发技术介绍 2 2.1 系统开发平台 2 2.2 平台开发相关技术 3 2.2.1 B/S架构 3 2.2.2 mysql数据库介绍 4 2.2.3 JSP技术介绍 4 第三章 系…

如何增强企业数字敏捷性?|身份云研究院

在经济下行背景中,企业面临数字化转型和降本增效两大课题,解决这两个问题的核心是增强企业数字敏捷性。比起从业务侧逐个优化,决策者们更应从数字化基础设施入手,搭好底层数字化架构来保障企业在不断变化的技术和法规中获得适应性…

随时随地查看远程试验数据与记录——IPEhub2与IPEmotion APP

一 背景 在工况恶劣、空间狭小的试验场景或工程机械领域中,不但试验人员在试验环境中对自身安全没有保障,而且试验过程也会受到影响,如高温高压测试、工程机械液压系统测试等。对此,结合IPEhub2与IPEmotion APP,既可保…

linux journalctl使用详解

1.概述 ​ journalctl 用来查询 systemd-journald 服务收集到的日志。systemd-journald 服务是 systemd init 系统提供的收集系统日志的服务。journalctl通常用来查询systemd管理的Unit的日志信息。 2.使用方法 $ man journalctl $ journalctl --help 常用方法 $ journalctl …

【可解释性机器学习】解释基于Scikit-learn进行文本分类的pipeline及结果

使用Scikit-learn进行文本分类pipeline1. 基线模型2. 基线模型,改进的数据3. Pipeline改进4. 基于字符的pipeline5. 调试HashingVectorizer参考资料scikit-learn文档提供了一个很好的文本分类教程。确保先阅读它。 本文中,我们将做类似的事情&#xff0c…

学习笔记-----通道

加粗样式# system v共享内存 进程通信的前提条件是:让不同进程看见同一份资源。 共享内存:其实就是进程获取共享区里面的地址,该地址为物理内存中某块我所需要资源的地址(该内存是创建的共享内存处在共享区里),地址通过页表映射到…

项目工时管理遇难题?看看这套工时管理系统解决方案

随着社会化大生产的发展以及市场竞争的日趋激烈,现代企业的规模在不断扩大。对于项目企业来说,人力资源的成本就是项目的主要成本,而工时是项目中人工成本的重要依据,因此,管理好员工工时是项目管理过程中最重要的任务…

计算机图形学 第3章 圆的扫描转换-第三章结束

书用的是 书名:计算机图形学基础教程(VisualC版)(第二版) 定价:44.5元 作者:孔令德 出版社:清华大学出版社 出版日期:2013-03-01 ISBN:9787302297529 目录习题3(续&#…

【数据结构】8.3 交换排序

文章目录1. 冒泡排序冒泡排序算法冒泡排序算法分析2. 快速排序快速排序算法快速排序算法分析基本思想 每两个元素之间互相比较,如果发现大小关系相反,则将他们交换过来,直到所有记录都排好序为止。假设希望是从小到大来排序,结果…

Nginx-反向代理配置学习总结

Nginx-反向代理配置学习总结 正向代理:指的是通过代理服务器 代理浏览器/客户端去重定向请求访问到目标服务器 的一种代理服务,正向代理服务的特点是代理服务器 代理的对象是浏览器/客户端,也就是对于目标服务器 来说浏览器/客户端是隐藏的。…

文件的IO

一、文件的定义狭隘的文件:指你的硬盘上的文件和目录.广义的文件:泛指计算机中的硬件资源,操作系统中,把很多硬件设备和软件资源都抽象成了文件,按照文件的形式统一管理.比如网卡,操作系统也是把网卡抽象成了文件资源,所以说操作网卡其实和操作文件的方式是基本一样的.而我们本…

初识流计算框架Spark

Spark简介 Spark最初由美国加州伯克利大学(UCBerkeley)的AMP(Algorithms, Machines and People)实验室于2009年开发,是基于内存计算的大数据并行计算框架,可用于构建大型的、低延迟的数据分析应用程序。Sp…

一刷代码随想录——链表

1.理论基础链表节点的定义:struct ListNode {int val;ListNode* next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode* next) : val(x), next(next) {} };根据卡哥提示,由于力扣中已经给出如…

C++中拷贝构造函数、拷贝赋值运算符、析构函数、移动构造函数、移动赋值运算符(三/五法则)

1、介绍 三五法则是针对C中类的成员和类对象的操作函数。 三法则是指:拷贝构造函数、拷贝赋值运算符、析构函数。 五法则是在三法则的基础上增加了:移动构造函数、移动赋值运算符。 2、拷贝构造函数 定义:如果构造函数的第一个参数是自身…

Postman前置脚本

位置:作用:调用脚本之前需要执行的代码片段一、产生随机数字生成0-1之间的随机数,包括0,不包括1;var random Math.random();console.log("随机数",random);获取最小值到最大值之前的整数随机数function Get…

2019-ICML-Graph U-Nets

2019-ICML-Graph U-Nets Paper: https://arxiv.org/abs/1905.05178 Code: https://github.com/HongyangGao/Graph-U-Nets 图U-Nets 作者将CNN上的U-Net运用到了图分类上,因为我们主题是图分类,就不对U-Net进行论述了,只对其中的gPool&#…