Python装饰器

【Python】新手入门:什么是python装饰器?如何使用python装饰器?什么是python类装饰器?什么是python内置装饰器? Python装饰器是一种高级功能,能够在不修改原代码的情况下动态增强函数或类的行为。其核心原理是通过嵌套函数包装目标函数,在调用前后添加额外逻辑,例如日志记录、性能分析或权限控制。装饰器语法简洁,使用@符号即可快速应用。它支持参数传递,也能通过多层嵌套实现复杂功能。此外,装饰器不仅适用于函数,还能扩展类功能,如实现单例模式或属性管理。内置装饰器如静态方法和类方法进一步简化了代码结构。这种设计模式显著提升了代码复用性和可维护性,是Python编程中极具特色的重要特性。 阅读详情

Python装饰器

转自:https://www.cnblogs.com/Yang-Sen/p/8670097.html

一、简介

1、开放封闭原则

在一个软件上线之后,就应当遵循开放封闭原则,即对修改原代码是封闭的,对功能的扩展是开放的,也就是在不修改一个源代码以及不改变调用的方式的前提下,为其加上新功能

2、什么是装饰器

装饰器就是在不修改被装饰对象源代码与调用方式的前提下,为被装饰对象添加新功能的工具。

装饰器是函数,被装饰的对象也是函数,装饰器与我们所了解闭包函数的逻辑相同

装饰器的原则组成:

< 函数+实参高阶函数+返回值高阶函数+嵌套函数+语法糖 = 装饰器 >

这个式子是贯穿装饰器的灵魂所在!

二、无参装饰器

2.1、无参装饰器模板

def outer(func):                   # 最原始的被装饰对象
    def inner(*args,**kwargs):
        res=func(*args,**kwargs)   # 调用被装饰对象
        return res
    return inner       

2.2、无参装饰器应用实例:

有代码如下:

import time
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122

很显然,我们可以看出这段代码肯定是等待1秒后打印'welcome to index page'

我们现在要在不改变源代码和调用方式的前提给程序添加统计时间的功能。

之前学习函数我们肯定也有了解,我们定义变量或者函数所对应的的值就会存到内存里面,我们如果想要调用这个变量或者函数的话就需要用到变量名或者函数名,一个名字对应的就是一个内存地址。我们调用名字就是在调用这个地址里面的内容。

高阶函数==>详解

高阶函数可以有两种形式:一种是把一个函数名当做实参传给另外一个函数(“实参高阶函数”),另一种是返回值中包含函数名(“返回值高阶函数”)

如果可以把函数名当做实参,那么也就是说可以把函数传递到另一个函数,然后在另一个函数里面做一些操作,根据这些分析来看,就满足了不修改源代码而增加功能。

但是我们还得满足不修改调用方式的条件,就是我们最后的执行代码也一定得是index(),这就用到第二种高阶函数,即返回值中包含函数名

但是装饰器真正的核心是闭包函数

另外还有一个需要注意的点,函数只能调用和它同级别以及上级的变量或函数。也就是说:里面的能调用和它缩进一样的和他外部的,而内部的是无法调用的。

现在我们可以满足那两个需求给函数添加功能

def timmer(func):
    #func=最原始的home
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs) #调用最原始的home
          stop_time=time.time()
        print(stop_time-start_time)
        return res
    return wrapper
index=timmer(index) #① 新的index=wrapper
index() # ②

在①处将函数名index作为参数传给了timmer(),所以现在timmer(func)=timmer(index),在接下来又在timmer函数内部定义了wrapper()函数,但是并未调用,而是在最后作为timmer函数的返回值,返回了wrapper函数的内存地址,

所以说timmer()得到的就是wrapper函数的地址,然后再把wrapper赋值给index,那么现在的index函数就不是原来的index了,而是经过timmer装饰器内部一系列的包装,返回的wrapper函数,在②处调用实际上是wrapper()。这段代码在本质是修改了调用函数,但是并没有修改原来的代码和原来的调用方式,而且增加了功能。

根据以上分析,装饰器在装饰的时候,需要在每个函数前面加上:

index = timmer(index)

 

相对来说比较麻烦,所以python为我们提供了一种简便快捷的方法,即语法糖 “@”

@timmer

这两句是等价的,只要在函数前加上这句,就可以实现装饰作用。

import time
def timmer(func):
    def wrapper():
        start_time=time.time()
        func()
        stop_time=time.time()
        print(stop_time-start_time)return wrapper

@timmer #index=timmer(index)
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122

以上内容都是基于被装饰函数没有参数传入,也没有返回值才会实现,但是往往一个函数是肯定会有参数的,而上述函数如果加上参数是肯定会报错的,因为index在调用的时候缺少一个位置参数,这个时候为了是程序更加具有扩展性,就需要为装饰器加上可变参数*args和**kwargs。

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print(stop_time-start_time)
        return res
    return wrapper

@timmer #index=timmer(index)
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122

我们通过“@”语法糖来调用装饰器的时候,需要注意一点,我们使用这个功能需要将“@+装饰器”在被装饰对象的正上方独占一行。

2.3、迭加多个装饰器

在实际的工作当中,我们可能会遇到需要不止添加加一个新功能的对象,这就需要我们用到多个装饰器进行迭加使用

 

import time
current_user={
    'username':None,
    # 'login_time':None
}

def auth(func):
    # func=index
    def wrapper(*args,**kwargs):
        if current_user['username']:
            print('已经登陆过了')
            res=func(*args,**kwargs)
            return res

        uname=input('用户名>>: ').strip()
        pwd=input('密码>>: ').strip()
        if uname == 'egon' and pwd == '123':
            print('登陆成功')
            current_user['username']=uname
            res=func(*args,**kwargs)
            return res
        else:
            print('用户名或密码错误')
    return wrapper
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print(stop_time-start_time)
        return res
    return wrapper
@auth
@timmer 
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122
index()

#  使用这种方式我们需要注意两个装饰器的先后顺序,在这个例子当中如果将“@timmer”放在“@anth”前面,那么“timmer”装饰器计算的就是auth+index的执行时间

从上面的代码我们可以看到函数装饰器的迭加使用,他们之间的执行时从上到下的,但是迭加的两个装饰器之间是离函数近的先装饰。

# 定义装饰器1
def set_log(func):
    print("__开始装饰set_log__")
    def call_func():
        print("__set_log__")
        func()
    return call_func

# 定义装饰器2
def set_func(func):
    print("__开始装饰set_func__")
    def call_func():
        print("__set_func__")
        func()
    return call_func


# 定义函数,并添加装饰器
@set_log    # 等价于 func1=set-log(func1)
@set_func  # 等价于    func1=set_func(func1)
def func1():
    print("__func__")
func1()

# 执行结果:
__开始装饰set_func__
__开始装饰set_log__
__set_log__
__set_func__
__func__

示例

三、有参装饰器

一个装饰器,对不同的函数有不同的装饰。那么就需要知道对哪个函数采取哪种装饰。因此,就需要装饰器带一个参数来标记一下。我们以往的装饰器,都是传递函数名字进去,而这次,多了一个参数,所以我们就需要再加一层函数来接受参数,根据嵌套函数的概念,要想执行内函数,就要先执行外函数,才能调用到内函数。

import time
current_user={
    'username':None,
    # 'login_time':None
}
def auth(engine):
    # engine='file'
    def auth2(func):
        # func=index
        def wrapper(*args,**kwargs):
            if engine == 'file':
                if current_user['username']:
                    print('已经登陆过了')
                    res=func(*args,**kwargs)
                    return res
                uname=input('用户名>>: ').strip()
                pwd=input('密码>>: ').strip()
                if uname == 'egon' and pwd == '123':
                    print('登陆成功')
                    current_user['username']=uname
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('用户名或密码错误')
            elif engine == 'mysql':
                print('基于MyQL的认证')
            elif engine == 'ldap':
                print('基于LDAP的认证')
        return wrapper
    return auth2
@auth('ldap') #@auth2 #index=auth2(index) #index=wrapper
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122
index() # wrapper()

四、装饰器补充:wraps

其实在我们初学装饰器的时候不会注意到这个问题,我们使用装饰器装饰过得函数其实已经不是之前的那个函数了,我们通过  " __doc__ " 方法是没办法调用查看我们被装饰函数的注释内容,所以说我们会为了消除这个副作用,在实现之前加上@wraps,这样就可以保留函数名和docstring。

from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper
@deco
def index():
    '''哈哈哈哈'''
    print('from index')

print(index.__doc__)

五、装饰器应用场景

  • 认证,权限的校验
  • 函数的事务处理,要么一起成功,要么一起失败
  • 插入日志,作为函数的运行日志
  • 缓存,实现缓存处理
  • 框架的路由传参
Python 装饰器 装饰器(decorators)是 Python 中的一种高级功能,它允许你动态地修改函数或类的行为。python的装饰器分三种:函数装饰器、类装饰器、内置装饰器装饰器的语法使用 @decorator_name 来应用在函数或方法上。Python 装饰允许在不修改原有函数代码的基础上,动态地增加或修改函数的功能,装饰器本质上是一个接收函数作为输入并返回一个新的包装过后的函数的对象。 阅读详情

相关推荐

win11下的MySQL安装

目前官方最新版本是8.0.26,考虑到其稳定性、可靠性还需一定周期保证,所以使用官方版求稳定仍然建议5.7系列。3、选择MySQL Servers 5.7.38 -x64,然后按绿色箭头将选中的版本移植到右边选中框中。4、点击下方蓝色Advanced Options,选择安装位置。1、在开始界面搜索MySQL,点击command line。4、在“系统变量”中选择“path”,点击编辑。5、新建——>增加MySQL路径——>确定,12、execute,安装好后next。9、不需要做修改,直接点击next。.

rensweet的博客 2万+

Python装饰器详解

详细介绍了Python装饰器语法的有关内容与使用技巧,希望对大家有所帮助。

千山暮彩 1万+

如何实现电路级别的CDM ESD防护

采用先进制程的CMOS工艺,可能具有比以前更薄的栅极氧化物和更大的芯片尺寸,大的衬底可能积累大量的电荷,导致CDM事件期间的高ESD放电峰值电流。传统CDM保护器件使用栅极接地NMOS被添加到输入级的栅极。然而,这种方法通常会在信号路径上引入显著的寄生电容,这不适合RF应用。

weixin_42693135的博客 2504

Python装饰器的实现和万能装饰器

Python装饰器的实现和万能装饰器 在Python中,装饰器是在不改变已有函数的代码的前提下,给函数增加新的功能的一种函数。 装饰器接收一个函数作为参数,返回值也是一个函数。 在Python中,实现装饰器的方式叫做闭包。 一、闭包的实现 闭包是指函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。 闭包的使用,可以隐藏内部函数的工作细节,只给外部...

weixin_43790276的博客 5987

centos 添加新硬盘,对根目录扩容

本地安装了虚拟机,系统为centos7,使用过程中,渐渐地发现磁盘容量不够用了,于是在虚拟机中新增了一块硬盘。 进入系统内查看: sdb是新增的硬盘,大小为40g。 接下来有两种方式,一种是普通方式直接挂载。https://blog.youkuaiyun.com/qq_39314099/article/details/106200322 这样的话只有在挂载点的目录下操作才能使用到这个新硬盘,不是很理想。 还有一种方式lvm,逻辑卷管理的方式。 LVM简单介绍: 它是 Linux 下对磁盘分区进行管

qq_39314099的博客 1万+

DOTS 性能基石:为什么传统 Unity 代码难以满足现代游戏需求?(DOTS 系列教程 · 第1篇)

本文探讨了Unity游戏开发中的性能优化问题,指出性能问题不应在最后才考虑,而应贯穿整个开发过程。文章分析了性能问题的三大表现(渲染开销、物理模拟、游戏逻辑),并解释了依赖硬件升级的不可行性。重点剖析了传统Unity代码性能低下的六大根源:垃圾回收卡顿、编译器优化不足、多核利用不足、数据结构和代码缓存不友好、过度抽象等问题。最后指出Unity项目中常见的反模式,如主线程垄断、内存碎片化等,为后续学习DOTS高性能架构解决方案奠定基础。

分享知识,拥抱变化 151

python中装饰器详解

装饰器 我们知道,在python中,我们可以像使用变量一样使用函,这主要依赖于以下几点: 函数可以被赋值给其他变量 函数可以被删除 可以在函数里面再定义函数,函数嵌套。 函数可以作为参数传递给另外一个函数 函数可以作为另一个函数的返回值 对一个简单的函数进行装饰 为了更好的理解装饰器,我们先从一个简单的例子开始,假设有下面这个函数: def hello(): return...

AFeng521web 7940

数据分析必问:Pandas面试题及参考答案

DataFrame是Pandas库中的一个核心数据结构,它类似于Excel中的表格,可以存储不同类型的数据。在Pandas中,抽样操作通常很简单,但是需要根据数据的特点和分析的需求来选择合适的抽样方法。数据标准化和归一化是数据预处理中常用的技术,目的是将数据调整到一个合适的范围内,以消除不同特征量纲和数值范围的差异,从而保证模型训练的有效性。CSV文件是一种文本文件,其中的数据以逗号分隔。不平衡数据集指的是数据集中各类别样本的数量差异较大的情况,这可能导致模型训练出现偏差,影响模型的泛化能力。

大模型大数据攻城狮的专栏 3009

【Python】装饰器

装饰器是 Python 中的一个强大工具,允许你在不改变函数本身的代码情况下,动态地修改或扩展其行为。装饰器通常用于日志记录、权限验证、缓存、性能监控等应用。你可以使用@decorator语法将装饰器应用到函数或方法上。装饰器是高阶函数,可以接受函数作为参数并返回一个新函数。

wq6qeg88的博客 2281

uniapp [全端兼容] - 最新详细实现拍摄视频录像并可播放预览视频,调起本机摄像头开启录像录制完毕后保存到本机临时存放,可对拍摄的视频进行压缩处理减少文件大小不损失画质,详解录制视频并读取播放!

uni-app,h5移动端网页,微信小程序,支付宝小程序,Android安卓,苹果ios,app,nvue,录视频,拍视频,拍摄录制视频后上传服务器,调起摄像头录视频并可预览,录视频上传,录像,uniapp录制视频并上传,录制视频并保存到本地设备,如何本地保存并播放预览,提供给用户观看MP4视频录像并上传到后端服务器完整功能源码,视频压缩,mp4文件,删除视频,录像后怎么预览,临时视频文件怎么减少压缩大小,视频压缩及上传,自己录视频并生成可播放的文件,录视频并能打开查看,视频压缩后上传,本机相册,录完怎么预

🏆 前端领域优质创作者 1万+

微信小程序 - 实现客户支付订单连接小票打印机自动打印订单小票功能,微信小程序如何对接小票打印机自动打印小票,小程序收到新订单的时候可以联动商家打印出小票/单据/标签/发货单/电子面单等(详细教程)

微信小程序调用小票打印机,小程序接单后小票机自动打印订单,微信小程序云开发订单微信支付与小票和标签打印的完整高效流程,如何实现微信订单连接小票打印机并自动接单打印,微信小程序连接打印机打印单据小票打印,微信小程序云开发调用小票打印机实现方案,微信小程序怎么配置小票打印机,微信支付电子小票,外卖小程序实战-接单后小票机自动打印订单,微信小程序连接蓝牙打印小票,打印购物小票,调用小票打印机打印小票,微信订单如何连接小票打印机并实现自动接单打印,实现微信订单连接小票打印机并自动接单打印,微信小程序小票打印机打印教

🏆 前端领域优质创作者 1万+

【python】python装饰器

Python装饰器(Decorator)是一种设计模式,允许你在不修改函数代码的前提下,增强或修改函数的功能。装饰器本质上是一个高阶函数,它接收一个函数作为参数,并返回一个增强后的函数。下面我们详细介绍Python装饰器的概念、使用场景及实现方法。

kissdragan的博客 1509

【25届数字IC秋招总结】面试经验13——豪威科技面试

25届数字ic面试记录———豪威科技

lalala0635的博客 363

python装饰器

学习目标:一口气把装饰器描述清楚 弄清楚装饰器前要理解三个东西: 函数对象、函数嵌套、函数构成闭包。 学习内容: 函数对象好说,python编程语言属于动态语言,python中一切皆对象,所以函数也是对象。 函数对象用函数名称表示(仅名称,没有括号,也没有参数)。 例如,定义了一个求和函数add,那么此处的add就是个函数对象。 def add(username, a, b): print(f"{a}+{b}={a + b}") return a + b 函数嵌套或者嵌套函数,就是定

人工智能视觉分析算法学习实践和经验分享。 3230

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

python装饰器class_python 装饰器详解

python装饰器详解python装饰器的详细解析什么是装饰器?推荐学习:Python视频教程python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能。这个函数的特殊之处在于它的返回值也是一个函数,这个函数是内嵌“原“”函数的函数。一般而言,我们要想拓展原来函数代码,最直接的办法就是侵入代码里面修...

weixin_39898550的博客 698

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【python】装饰器

在Python中,装饰器(decorators)是一种高级功能,它允许你在不修改原有函数或方法代码的情况下,给函数或方法添加新的功能。装饰器本质上是一个返回函数的函数,它接受一个函数作为参数,并返回一个新的函数(有时是对原函数的封装或修改)。

morris 1万+

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

【Python】Python装饰器

python装饰器 函数装饰器 类装饰器 单例模式

@苏丶的博客 1032

[Python]装饰器

1. 装饰器的定义 1.1 装饰器的功能特点 2. 装饰器的示例代码 3. 装饰器的语法糖写法 4. 装饰器的执行时机 5. 装饰器的使用 5.1 装饰器的使用场景 5.2 装饰器实现已有函数执行时间的统计 6. 通用装饰器的使用 6.1 装饰带有参数的函数 6.2 装饰带有参数和返回值的函数 6.3 装饰带有不定长参数和返回值的函数 6.4 通用装饰器 7. 多个装饰器的使用 8. 带有参数的装饰器 9. 类装饰器的使用

emmmm..... 1337

python装饰器_Python装饰器

装饰器前缘Python装饰器对于Python初学者可能是一个比较抽象的概念,在了解装饰器之前,我们必须先熟悉Pythond方法的一个特性:Python中的方法可以像普通变量一样当做参数传递给另外一个方法,我们来看一个例子:def add(x,y): return x+ydef sub(x,y): return x-ydef apply(func,x,y): return...

weixin_40003233的博客 183

【python】装饰器详解

本文将带你学习装饰器在 Python 中的工作原理,如果在函数和类中使用装饰器,如何利用装饰器避免代码重复(DRY 原则,Don’t Repeat Yourselfdef __init__(self, a, *args, **kwargs): # 类装饰器参数self.a = adef __call__(self, func): # 被装饰函数print("开始调用example函数..............")example()self.a = a# @语法糖等价形式。

z099164的博客 1050

Python装饰器注解

我的标题第一章 引言第1节 装饰器定义第2节 装饰器的使用背景第3节 装饰器的使用场景第4节 装饰器的优缺点第二章 python中的装饰器第1节 实现对象第2节 简单装饰器demo第3节 带参数的装饰器 第一章 引言 第1节 装饰器定义 在面向对象(OOP)的设计模式中,Decorator被称为装饰模式,OOP的装饰器模式需要通过继承和组合来实现。 本质上,装饰器是一个类或带有返回函数的高阶函数。 第2节 装饰器的使用背景 一般的,我们为了扩展一个类经常使用继承方式来实现,由于继承给类引入了新的静态特征,并

Hannah_000的博客 1136

python 装饰器有哪些_Python装饰器

一, 引用二, 基本概念问题1:装饰器是什么?解答:严格来说,装饰器只是语法糖, 装饰器是可调用的对象,可以像常规的可调用对象那样调用,特殊的地方是装饰器的参数是一个函数问题2:装饰器有什么特性?解答: 装饰器有2个特性,一是可以把被装饰的函数替换成其他函数, 二是可以在加载模块时候立即执行def decorate(func):print('running decorate', func)def ...

weixin_39870092的博客 1158
上一篇: 取消Chrome黑暗模式
下一篇: Python-微信机器人
Estrellas_
博客等级 码龄9年 273粉丝 233原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值