恶补Python 装饰器的六种写法,最强干货

Python基础篇(十一):装饰器 装饰器是Python中一种强大的函数或类修饰机制,用于在不修改原始函数或类代码的情况下,对其进行功能扩展或修改。装饰器基于函数式编程的概念,通过将函数作为参数传递给另一个函数,并返回一个新的函数来实现。装饰器是一个函数,它接受一个函数作为输入,并返回一个新的函数作为输出。装饰器可以在不修改原始函数的情况下,为其添加额外的功能或修改其行为。(感觉像java中的面向切面编程~) 阅读详情

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理

今天给大家分享一下关于装饰器的知识点,内容非常干,全程高能,认真吸收看完,一定会对装饰器有更深的理解。

Hello,装饰器

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

装饰器的使用方法很固定

  • 先定义一个装饰器(帽子)
  • 再定义你的业务函数或者类(人)
  • 最后把这装饰器(帽子)扣在这个函数(人)头上

就像下面这样子

# 定义装饰器
def decorator(func):
    def wrapper(*args, **kw):
        return func()
    return wrapper

# 定义业务函数并进行装饰
@decorator
def function():
    print("hello, decorator")
复制代码

实际上,装饰器并不是编码必须性,意思就是说,你不使用装饰器完全可以,它的出现,应该是使我们的代码

  • 更加优雅,代码结构更加清晰
  • 将实现特定的功能代码封装成装饰器,提高代码复用率,增强代码可读性

接下来,我将以实例讲解,如何编写出各种简单及复杂的装饰器。

第一种:普通装饰器

首先咱来写一个最普通的装饰器,它实现的功能是:

  • 在函数执行前,先记录一行日志
  • 在函数执行完,再记录一行日志
# 这是装饰器函数,参数 func 是被装饰的函数
def logger(func):
    def wrapper(*args, **kw):
        print('我准备开始执行:{} 函数了:'.format(func.__name__))

        # 真正执行的是这行。
        func(*args, **kw)

        print('主人,我执行完啦。')
    return wrapper
复制代码

假如,我的业务函数是,计算两个数之和。写好后,直接给它带上帽子。

@logger
def add(x, y):
    print('{} + {} = {}'.format(x, y, x+y))
复制代码

然后执行一下 add 函数。

add(200, 50)
复制代码

来看看输出了什么?

我准备开始执行:add 函数了:
200 + 50 = 250
我执行完啦。
复制代码

第二种:带参数的函数装饰器

通过上面两个简单的入门示例,你应该能体会到装饰器的工作原理了。

不过,装饰器的用法还远不止如此,深究下去,还大有文章。今天就一起来把这个知识点学透。

回过头去看看上面的例子,装饰器是不能接收参数的。其用法,只能适用于一些简单的场景。不传参的装饰器,只能对被装饰函数,执行固定逻辑。

装饰器本身是一个函数,做为一个函数,如果不能传参,那这个函数的功能就会很受限,只能执行固定的逻辑。这意味着,如果装饰器的逻辑代码的执行需要根据不同场景进行调整,若不能传参的话,我们就要写两个装饰器,这显然是不合理的。

比如我们要实现一个可以定时发送邮件的任务(一分钟发送一封),定时进行时间同步的任务(一天同步一次),就可以自己实现一个 periodic_task (定时任务)的装饰器,这个装饰器可以接收一个时间间隔的参数,间隔多长时间执行一次任务。

可以这样像下面这样写,由于这个功能代码比较复杂,不利于学习,这里就不贴了。

@periodic_task(spacing=60)
def send_mail():
     pass
  
@periodic_task(spacing=86400)
def ntp()
    pass 
复制代码

那我们来自己创造一个伪场景,可以在装饰器里传入一个参数,指明国籍,并在函数执行前,用自己国家的母语打一个招呼。

# 小明,中国人
@say_hello("china")
def xiaoming():
    pass

# jack,美国人
@say_hello("america")
def jack():
    pass
复制代码

那我们如果实现这个装饰器,让其可以实现 传参 呢?

会比较复杂,需要两层嵌套。

def say_hello(contry):
    def wrapper(func):
        def deco(*args, **kwargs):
            if contry == "china":
                print("你好!")
            elif contry == "america":
                print('hello.')
            else:
                return

            # 真正执行函数的地方
            func(*args, **kwargs)
        return deco
    return wrapper
复制代码

来执行一下

xiaoming()
print("------------")
jack()
复制代码

看看输出结果。

你好!
------------
hello.
复制代码

第三种:不带参数的类装饰器

以上都是基于函数实现的装饰器,在阅读别人代码时,还可以时常发现还有基于类实现的装饰器。

基于类装饰器的实现,必须实现 __call__ 和 __init__两个内置函数。 __init__ :接收被装饰函数 __call__ :实现装饰逻辑。

还是以日志打印这个简单的例子为例

class logger(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("[INFO]: the function {func}() is running..."\
            .format(func=self.func.__name__))
        return self.func(*args, **kwargs)

@logger
def say(something):
    print("say {}!".format(something))

say("hello")
复制代码

执行一下,看看输出

[INFO]: the function say() is running...
say hello!
复制代码

第四种:带参数的类装饰器

上面不带参数的例子,你发现没有,只能打印INFO级别的日志,正常情况下,我们还需要打印DEBUG WARNING等级别的日志。 这就需要给类装饰器传入参数,给这个函数指定级别了。

带参数和不带参数的类装饰器有很大的不同。

__init__ :不再接收被装饰函数,而是接收传入参数。 __call__ :接收被装饰函数,实现装饰逻辑。

class logger(object):
    def __init__(self, level='INFO'):
        self.level = level

    def __call__(self, func): # 接受函数
        def wrapper(*args, **kwargs):
            print("[{level}]: the function {func}() is running..."\
                .format(level=self.level, func=func.__name__))
            func(*args, **kwargs)
        return wrapper  #返回函数

@logger(level='WARNING')
def say(something):
    print("say {}!".format(something))

say("hello")
复制代码

我们指定WARNING级别,运行一下,来看看输出。

[WARNING]: the function say() is running...
say hello!
复制代码

第五种:使用偏函数与类实现装饰器

绝大多数装饰器都是基于函数和闭包实现的,但这并非制造装饰器的唯一方式。

事实上,Python 对某个对象是否能通过装饰器( @decorator)形式使用只有一个要求:decorator 必须是一个“可被调用(callable)的对象。

对于这个 callable 对象,我们最熟悉的就是函数了。

除函数之外,类也可以是 callable 对象,只要实现了__call__ 函数(上面几个例子已经接触过了)。

还有容易被人忽略的偏函数其实也是 callable 对象。

接下来就来说说,如何使用 类和偏函数结合实现一个与众不同的装饰器。

如下所示,DelayFunc 是一个实现了 __call__ 的类,delay 返回一个偏函数,在这里 delay 就可以做为一个装饰器。(以下代码摘自 Python工匠:使用装饰器的小技巧)

import time
import functools

class DelayFunc:
    def __init__(self,  duration, func):
        self.duration = duration
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f'Wait for {self.duration} seconds...')
        time.sleep(self.duration)
        return self.func(*args, **kwargs)

    def eager_call(self, *args, **kwargs):
        print('Call without delay')
        return self.func(*args, **kwargs)

def delay(duration):
    """
    装饰器:推迟某个函数的执行。
    同时提供 .eager_call 方法立即执行
    """
    # 此处为了避免定义额外函数,
	# 直接使用 functools.partial 帮助构造 DelayFunc 实例
    return functools.partial(DelayFunc, duration)
复制代码

我们的业务函数很简单,就是相加

@delay(duration=2)
def add(a, b):
    return a+b
复制代码

来看一下执行过程

>>> add    # 可见 add 变成了 Delay 的实例
<__main__.DelayFunc object at 0x107bd0be0>
>>> 
>>> add(3,5)  # 直接调用实例,进入 __call__
Wait for 2 seconds...
8
>>> 
>>> add.func # 实现实例方法
<function add at 0x107bef1e0>
复制代码

第六种:能装饰类的装饰器

用 Python 写单例模式的时候,常用的有三种写法。其中一种,是用装饰器来实现的。

以下便是我自己写的装饰器版的单例写法。

instances = {}

def singleton(cls):
	def get_instance(*args, **kw):
		cls_name = cls.__name__
		print('===== 1 ====')
		if not cls_name in instances:
			print('===== 2 ====')
			instance = cls(*args, **kw)
			instances[cls_name] = instance
		return instances[cls_name]
	return get_instance

@singleton
class User:
	_instance = None

	def __init__(self, name):
		print('===== 3 ====')
		self.name = name
复制代码

可以看到我们用singleton 这个装饰函数来装饰 User 这个类。装饰器用在类上,并不是很常见,但只要熟悉装饰器的实现过程,就不难以实现对类的装饰。在上面这个例子中,装饰器就只是实现对类实例的生成的控制而已。

其实例化的过程,你可以参考我这里的调试过程,加以理解。

以上就是我对装饰器的总结,内容非常多,通读一遍一定会对你理解装饰器有帮助~

想要获取更多Python学习资料可以加
QQ:2955637827私聊
或加Q群630390733
大家一起来学习讨论吧!

 

【论文+代码】ZS-N2N实现小样本零网络图像去噪 本文涵盖论文原文讲解与代码复现。 阅读详情

相关推荐

AIGC内容溯源技术:如何追踪AI生成内容的原始来源

本文旨在系统性地介绍AIGC内容溯源的技术体系,帮助读者理解如何追踪AI生成内容的来源。我们将覆盖从基础概念到前沿技术的完整知识链,包括但不限于数字水印、区块链存证、内容指纹等技术方案。文章将从AIGC的基本概念出发,逐步深入探讨各种溯源技术,分析其原理和实现,最后讨论实际应用和未来趋势。AIGC:AI Generated Content,人工智能生成内容内容溯源:追踪数字内容的创作、修改和传播历史数字水印:嵌入在数字内容中的不可见识别信息数字水印:隐藏在内容中的识别信息,像隐形墨水内容指纹。

SuperAGI2025 2071

Python学习之——装饰器

Python学习之——装饰器

selfsongs 2万+

Tableau学习教程(万字保姆级教程)​​​​​​

​Tableau学习教程(保姆级教材,学不会私信留言来找我) 从BI系统开发的角度来学习tableau工具,更学会报表开发的流程 内含学习使用数据源,tableau打包工作簿,可直接提取使用 ​...

小菜菜的博客 6万+

python-装饰器

Python 中的装饰器是一种语法糖,可以在运行时,动态的给函数或类添加功能。装饰器本质上是一个函数,使用@ + 函数名就是可实现绑定给函数的第二个功能。将一些通用的、特定函数的功能抽象成一个装饰器,可以重复利用这些功能“装饰”代指为被装饰对象添加新的功能,“器”代指器具/工具装饰器的作用:就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。插入日志、性能测试、事务处理、缓存、权限校验函数、方法、类函数装饰器分为:无参装饰器和有参装饰,二者都是使用都是需要【

王献运的博客 2万+

深入解析 Fiori Launchpad Notification:架构、配置与用户体验全景

开发者可继承接口,在注册自研 Provider,利用实例化消息;若想批量推送,可用API (

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 436

Vek385评估板(二):板子联网 & memtester安装(LPDDR5X测试)

继上一篇文章:Vek385评估板(一):EDF成功烧录启动及一些问题。 本章完成最主要的两个功能:开发板联网+内存 memtester。因为我是做测试行业的,所以这两个是最想试的。内存测试,除了FPGA测,也可以系统级测,本次在versal上实现这个功能,主要是可以应急。在没有安卓、X86的情况下,可以使用本方案测试。 下一篇会继续做一些其他功能。

千歌叹尽执夏的博客 222

python装饰器详解

python装饰器

weixin_44992737的博客 8万+

【网络与爬虫 53】Scrapy-Prometheus实战指南:打造企业级爬虫监控体系的终极解决方案

本文深入探讨Scrapy-Prometheus集成技术,通过费曼学习法从监控痛点出发,详细讲解如何在Scrapy爬虫中集成Prometheus指标收集系统。涵盖从基础配置到企业级监控体系的完整实战指南,帮助开发者构建可观测性强、可维护性高的分布式爬虫监控平台,实现爬虫性能的精准监控和智能告警。

熵数实验室 1584

Python的装饰器

本篇文章介绍了python的装饰器是如何实现的,还有大家都经常听到的语法糖的讲解

m0_72154565的博客 8584

Android 13 wificond讲解

Android 13 wificond讲解

专业开发者的博客,一个从事Android WiFi和蓝牙的工程师 2932

姿态传感器/陀螺仪之LSM6DSLTR应用驱动程序设计

* LSM6DSLTR I2C地址(SA0=1) *//* 初始化LSM6DSLTR传感器(加速度计±2g,陀螺仪±250°/s) *//* 加速度计灵敏度 *//* 角速度值(°/s) *//* I2C句柄 *//* 陀螺仪灵敏度 *//* 加速度值(g) *//* 温度值(°C) *//* 设备地址 *//* IF_INC=1: 自动增量地址 *//* 10Hz采样率 *//* 配置I2C1引脚:PB6->SCL, PB7->SDA *//* 转换为实际温度值(°C),参考手册中温度计算公式 */

corlin6688的博客 395

Python装饰器详解

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

千山暮彩 1万+

17、非线性动力学特征在情感语音与食管语音分析中的应用

本文探讨了非线性动力学特征在情感语音与食管语音分析中的应用。在情感语音识别中,选取Hurst指数、相关维数和Lempel-Ziv复杂度等混沌特征结合统计量,通过神经网络实现了中性、恐惧和愤怒情感的高效分类,全局成功率高达93.78%。在食管语音分析中,针对其缺乏明显周期性的问题,提出基于改进自相关方法的基频测量流程,包括包络计算、平滑与峰值细化,并对基频的物理意义提出思考。研究展示了两类语音在特征表现与技术方法上的差异,展望了其在客服、安全、医疗康复等领域的应用前景,并指出了未来在特征拓展、算法优化和发声机

sunny的博客 75

Python 装饰器

Python 装饰器(Decorator)是一种用于修改或扩展函数或方法行为的工具。它允许在不改变原函数代码的情况下,动态地添加功能。装饰器本质上是一个闭包函数,接受一个函数作为参数并返回一个新的函数。

大龄程序员 6033

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Python-装饰器详解

在Python中,装饰器是一种特殊的语法,用于修改或增强函数的功能。装饰器是Python的高级特性之一,它允许我们通过在不修改原函数代码的情况下,添加额外的功能或行为。装饰器是一个函数,它接受一个函数作为参数,并返回一个新的函数。装饰器函数通常使用符号放在要修饰的函数定义之前python中的装饰器(decorator)一般采用语法糖的形式,是一种语法格式。比如:@classmethod,@staticmethod,@property,@wraps(),等都是python中的装饰器。

qq_51010919的博客 2705

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Python装饰器:高效代码增强利器

Python装饰器是一种高阶函数,可以在不修改原函数代码的前提下动态扩展功能。其核心原理是通过闭包和函数作为一等对象的特性实现包装逻辑,使用@语法糖简化调用。

an_yu_xin的博客 3012

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

python装饰器(Decorator)

python装饰器(Decorator)

棠越的博客 9679

python之修饰器介绍及示例

Python 中的装饰器是一个非常强大的功能,它允许你在不修改函数本身代码的情况下,对函数的行为进行扩展或修改。装饰器本质上是一个函数,它接受一个函数作为参数,返回一个新的函数,并且新函数的行为与原函数不同。

yueguang8的博客 1214

python中的装饰器(基础装饰器)

1. 什么是装饰器 2. 装饰器的实现原理 3.装饰器的作用

qq_44690947的博客 8508

Web安全和渗透测试有什么关系?

做渗透测试的一个环节就是测试web安全,需要明白漏洞产生原理,通过信息收集互联网暴露面,进行漏洞扫描,漏洞利用,必要时进行脚本自编写和手工测试,力求挖出目标存在的漏洞并提出整改建议,当然如果技术再精一些,还要学习内网渗透(工作组和域环境),白盒审计,app,小程序渗透那些了......可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。总之,web安全包含于渗透测试,但不是渗透测试的全部。

Python_0011的博客 4858

python 10个好用的装饰器(非常详细)零基础入门到精通,收藏这一篇就够了

Python装饰器是一种特殊类型的函数,它可以修改或增强其他函数的功能,而无需更改原始函数的源代码。装饰器本质上是一个接收函数作为参数的函数,它返回一个新的函数或者修改过的原函数,通常用于插入日志、性能测试、权限校验、缓存、事务处理等场景。用于测量函数执行时间。记录函数调用的日志。利用functools.lru_cache实现结果缓存,避免重复计算。确保函数参数类型正确。确保类的实例唯一。在异常发生时自动重试。使用cProfile进行性能分析。确保用户已登录。用于异步操作。确保输入满足特定条件。

Hacker_j1的博客 2382

Python--装饰器详解

一、基本概念。

墨上烟雨 1788

【python】装饰器:decorator

python装饰器。

风高秋月白,雨霁晚霞红 3424

【Python】装饰器

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

wq6qeg88的博客 2277

Python装饰器简介(Python Decorator)

装饰器的本质就和它的名字一样,是用来"装饰"其他对象的,通过在原始函数上加一层"包装",在不修改原代码的情况下进行功能扩展,就像人可以穿不同的衣服来"装饰"自己一样。

最简单的方法,解决最实际的问题。 1535

一文看懂Python系列之装饰器(decorator)

python的装饰器可以在不修改源代码和调用方式的前提下为被装饰对象添加新功能

qq_44955314的博客 1633
上一篇: Python进阶——什么是描述符?
下一篇: 从函数到包的Python代码层次
pythonputao
博客等级 码龄6年 60粉丝 111原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值