Python的装饰器介绍

Python装饰器是一个强大的工具,可以增强函数或方法的功能而不改变它们的源代码。装饰器本质上是高阶函数(即接受一个函数作为参数的函数),它允许我们在函数的入口和出口添加逻辑,这使得代码更简洁、更具可维护性。下面是对Python装饰器的详细介绍。

1. 装饰器的基本概念

装饰器是一种函数,用于修改或扩展其他函数或方法的行为。它接受一个函数作为参数,并返回一个新的函数。装饰器通常使用@语法糖来应用到函数上。

基本示例

 

def simple_decorator(f): def wrapper(): print("Something is happening before the function is called.") f() print("Something is happening after the function is called.") return wrapper @simple_decorator def say_hello(): print("Hello!") say_hello()

在上面的示例中,simple_decorator函数是一个装饰器,它接受say_hello函数并返回一个新的wrapper函数。wrapper函数在调用f()(即say_hello)之前和之后打印消息。

2. 装饰器的应用场景

2.1 日志记录

装饰器可以用于添加日志记录功能,以便在调用函数时记录日志信息。

 

def log_decorator(f): def wrapper(*args, **kwargs): print(f"Calling function {f.__name__} with arguments {args} and keyword arguments {kwargs}") result = f(*args, **kwargs) print(f"Function {f.__name__} returned {result}") return result return wrapper @log_decorator def add(a, b): return a + b add(2, 3)

2.2 访问控制

装饰器可以用于检查用户权限或其他访问控制措施。

 

def requires_admin(f): def wrapper(*args, **kwargs): user = kwargs.get('user', None) if user is not None and user.get('is_admin', False): return f(*args, **kwargs) else: raise PermissionError("User does not have the required permissions.") return wrapper @requires_admin def delete_user(user_id, user): print(f"User {user_id} has been deleted.") # 示例用法 admin_user = {'username': 'admin', 'is_admin': True} regular_user = {'username': 'guest', 'is_admin': False} delete_user(123, user=admin_user) # 正常执行 delete_user(123, user=regular_user) # 引发PermissionError

2.3 缓存

装饰器可以用于实现函数的缓存,以提高性能。

 

from functools import lru_cache @lru_cache(maxsize=None) def fibonacci(n): if n < 2: return n return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(30))

3. 函数装饰器和类装饰器

除了装饰函数,装饰器还可以用于类。这使得装饰器在面向对象编程中同样强大。

3.1 类装饰器

类装饰器是用于修改类行为的装饰器。它们接收一个类,并返回一个新的类或修改后的类。

 

def add_str_repr(cls): def __str__(self): return f"{self.__class__.__name__} with attributes {self.__dict__}" cls.__str__ = __str__ return cls @add_str_repr class Person: def __init__(self, name, age): self.name = name self.age = age p = Person("Alice", 30) print(p)

3.2 方法装饰器

方法装饰器与函数装饰器类似,但它们用于类的方法。

 

def log_method_call(method): def wrapper(self, *args, **kwargs): print(f"Calling method {method.__name__} with arguments {args} and keyword arguments {kwargs}") return method(self, *args, **kwargs) return wrapper class Person: def __init__(self, name, age): self.name = name self.age = age @log_method_call def greet(self): print(f"Hello, my name is {self.name}") p = Person("Alice", 30) p.greet()

4. 参数化装饰器

参数化装饰器允许我们传递参数给装饰器。为了实现这一点,我们需要创建一个返回装饰器的函数。

 

def repeat(n): def decorator(f): def wrapper(*args, **kwargs): for _ in range(n): f(*args, **kwargs) return wrapper return decorator @repeat(3) def say_hello(): print("Hello!") say_hello()

在上面的示例中,repeat函数是一个参数化装饰器工厂,它返回一个装饰器,该装饰器会将目标函数执行指定的次数。

5. 内置装饰器

Python 提供了一些内置的装饰器,如@staticmethod@classmethod@property,它们用于不同的用途。

5.1 @staticmethod

@staticmethod装饰器用于定义静态方法,即不需要访问实例或类的属性和方法。

 

class Math: @staticmethod def add(a, b): return a + b print(Math.add(3, 5))

5.2 @classmethod

@classmethod装饰器用于定义类方法,即可以访问类本身的属性和方法。

 

class Math: _pi = 3.14 @classmethod def get_pi(cls): return cls._pi print(Math.get_pi())

5.3 @property

@property装饰器用于定义属性方法,即可以像属性一样访问的方法。

 

class Circle: def __init__(self, radius): self._radius = radius @property def radius(self): return self._radius @radius.setter def radius(self, value): if value <= 0: raise ValueError("Radius must be positive") self._radius = value c = Circle(5) print(c.radius) c.radius = 10 print(c.radius)

6. 多重装饰器

一个函数可以同时应用多个装饰器,这些装饰器将从内到外依次应用。

 

def bold(f): def wrapper(): return f"<b>{f()}</b>" return wrapper def italic(f): def wrapper(): return f"<i>{f()}</i>" return wrapper @bold @italic def greet(): return "Hello" print(greet())

在上面的示例中,greet函数首先应用@italic装饰器,然后应用@bold装饰器,最终结果是Hello被加粗和斜体显示。

7. 装饰器的实现细节

为了更好地理解装饰器的工作原理,让我们深入探讨一下装饰器的实现细节。

7.1 保持函数元数据

使用functools.wraps装饰器可以确保装饰器不会丢失原始函数的元数据,如名称和文档字符串。

from fuctools import wraps def simple_decorator(f): @wraps(f) def wrapper(*args, **kwargs): print("Something is happening before the function is called.") result = f(*args, **kwargs) print("Something is happening after the function is called.") return result return wrapper @simple_decorator def say_hello(): """This function says hello""" print("Hello!") print(say_hello.__name__) print(say_hello.__doc__)

7.2 处理带参数的装饰器

带参数的装饰器需要多一层包装,以便接收参数。

def decorator_with_args(arg1, arg2): def decorator(f): @wraps(f) def wrapper(*args, **kwargs): print(f"Decorator arguments: {arg1}, {arg2}") return f(*args, **kwargs) return wrapper return decorator @decorator_with_args("hello", "world") def greet(name): print(f"Hello, {name}") greet("Alice")

总结

Python装饰器是一个强大的工具,可以在不修改原始函数或方法的情况下扩展其功能。通过装饰器,我们可以实现日志记录、访问控制、缓存、性能优化等多种功能。此外,装饰器可以应用于函数、方法和类,使得它们在函数式编程和面向对象编程中都能发挥重要作用。理解和熟练应用装饰器将极大地提高代码的可维护性和可重用性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis源码整体结构

一 前言 Redis源码研究为什么先介绍整体结构呢?其实也很简单,作为程序员的,要想对一个项目有快速的认知,对项目整体目录结构有一个清晰认识,有助于我们更好的了解这个系统。 二 目录结构 Redis源码download到本地之后,对应结构如下: 从上面的截图可以看出,Redis源码一…

【密码学】信息安全五大属性

信息安全的五大属性&#xff0c;通常被称为CIA三元组加上两个额外的属性&#xff0c;他们是确保信息在存储、处理和传输过程中保持安全、完整和可用的关键要素。这些属性共同构成了信息安全的基础框架。 一、信息安全五大属性 我先给出一个直观的列表&#xff0c;方面大家后续…

BigDecimal(double)和BigDecimal(String)有什么区别?BigDecimal如何精确计数?

BigDecimal(double)和BigDecimal(String)的区别 double是不精确的&#xff0c;所以使用一个不精确的数字来创建BigDecimal&#xff0c;得到的数字也是不精确的。如0.1这个数字&#xff0c;double只能表示他的近似值。所以&#xff0c;当我们使用new BigDecimal(0.1)创建一个Bi…

69.WEB渗透测试-信息收集- WAF、框架组件识别(9)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;68.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;8&#xff09; 有无waf存在&am…

前端必修技能:高手进阶核心知识分享 - CSS 阴影属性详解

CSS 涉及设计到阴影的相关内容包括三个方面&#xff1a;box-shadow属性&#xff08;盒子阴影&#xff09;、 text-shadow属性&#xff08;文本阴影&#xff09;、drop-shadow滤镜。 本篇文章旨在详细介绍和分析三种阴影的具体参数设置和典型用例。 box-shadow属性&#xff08;…

蚂蚁全媒体总编刘鑫炜谈新媒体时代艺术家如何创建及提升个人品牌

新媒体时代艺术家如何创建及提升个人品牌形象——专访蚂蚁全媒体总编刘鑫炜 图为蚂蚁全媒体总编刘鑫炜 在新媒体风潮席卷全球的今天&#xff0c;传统艺术与新媒体技术的融合越来越紧密。这种变革不仅改变了艺术作品的呈现方式&#xff0c;也给艺术家们提供了更多的可能性。那么…

从FasterTransformer源码解读开始了解大模型(2.1)代码通读03

从FasterTransformer源码解读开始了解大模型&#xff08;2.2&#xff09;代码解读03-forward函数 写在前面的话 本篇的内容继续解读forward函数&#xff0c;从650行开始进行解读 零、输出Context_embeddings和context_cum_log_probs的参数和逻辑 从653行开始&#xff0c;会…

怎样让家长单独查到自己孩子的期末成绩?

期末考试的钟声已经敲响&#xff0c;随着最后一份试卷的收卷&#xff0c;学生们的紧张情绪渐渐平息。然而&#xff0c;对于老师们来说&#xff0c;这仅仅是另一个忙碌周期的开始。成绩的统计、分析、反馈&#xff0c;每一项工作都不容小觑。尤其是将成绩单一一私信给家长&#…

【Python】组合数据类型:序列,列表,元组,字典,集合

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️Python】 文章目录 前言组合数据类型序列类型序列常见的操作符列表列表操作len()append()insert()remove()index()sort()reverse()count() 元组三种序列类型的区别 集合类型四种操作符集合setfrozens…

分子AI预测赛Task4笔记(结束)

话不多说&#xff0c;直接上官方链接&#xff1a;‌​​​‍&#xfeff;​⁠​‌​‍​​&#xfeff;​‌​⁠‬​&#xfeff;‬​​‌​​​​‬‬​​​​‍⁠‍‌​&#xfeff;⁠Task3&#xff1a;进阶baseline详解 - 飞书云文档 (feishu.cn)Task4&#xff1a;持续尝试&…

RAID的实现

软RAID&#xff0c;在实际工作中使用较少&#xff0c;性能太次。 mdadm工具&#xff0c;主要在虚拟机上使用&#xff0c; 硬RAID 用一个单独的芯片&#xff0c;这个芯片的名字叫做RAID卡&#xff0c;数据在RAID中进行分散的时候&#xff0c;用的就是RAID卡。 模拟RAID-5工作…

【Transformer】transformer模型结构学习笔记

文章目录 1. transformer架构2. transformer子层解析3. transformer注意力机制4. transformer部分释疑 图1 transformer模型架构 图2 transformer主要模块简介 图3 encoder-decoder示意图N6 图4 encoder-decoder子层示意图 1. transformer架构 encoder-decoder框架是一种处理NL…

AI编程探索- iOS 实现类似苹果地图 App 中的半屏拉起效果

想要的效果 功能分析 想要实现这种效果&#xff0c;感觉有点复杂&#xff0c;于是就想搜一下相关资料看看&#xff0c;可问题是&#xff0c;我不知道如何描述这种效果&#x1f602;。 当我们遇到这种效果看着很熟悉&#xff0c;但是不知道如何描述它具体是什么的时候&#…

有一个日期(Date)类的对象和一个时间(Time)类的对象,均已指定了内容,要求一次输出其中的日期和时间

可以使用友元成员函数。在本例中除了介绍有关友元成员函数的简单应用外&#xff0c;还将用到类的提前引用声明&#xff0c;请读者注意。编写程序&#xff1a; 运行结果&#xff1a; 程序分析&#xff1a; 在一般情况下&#xff0c;两个不同的类是互不相干的。display函…

华为云OBS 通过S3客户端访问

华为云好像没有对S3协议的支持说明其实底层是支持S3协议的。 使用S3的时候我们会需要endpoint&#xff0c;桶名字&#xff0c;region&#xff0c;AWS_ACCESS_KEY,AWS_SECRET_KEY 其中endpoint 就是图片中的&#xff0c;桶名字也很容易找到&#xff0c;region 就是你的endpoint…

Nestjs基础

一、创建项目 1、创建 安装 Nest CLI&#xff08;只需要安装一次&#xff09; npm i -g nestjs/cli 进入要创建项目的目录&#xff0c;使用 Nest CLI 创建项目 nest new 项目名 运行项目 npm run start 开发环境下运行&#xff0c;自动刷新服务 npm run start:dev 2、…

Maven一键配置阿里云远程仓库,让你的项目依赖飞起来!

文章目录 引言一、为什么选择阿里云Maven仓库&#xff1f;二、如何设置Maven阿里云远程仓库&#xff1f;三、使用阿里云Maven仓库的注意事项总结 引言 在软件开发的世界里&#xff0c;Maven无疑是一个强大的项目管理工具&#xff0c;它能够帮助我们自动化构建、依赖管理和项目…

C++初学者指南-5.标准库(第一部分)--迭代器

C初学者指南-5.标准库(第一部分)–迭代器 Iterators 文章目录 C初学者指南-5.标准库(第一部分)--迭代器 Iterators1.默认正向迭代器2.反向迭代器3.基于迭代器的循环4.示例&#xff1a;交换相邻的一对元素5.迭代器范围6.迭代器范围中的元素数量7. 总结&#xff1a;迭代器 指向某…

动态规划|剑指 Offer II 093. 最长斐波那契数列

如果数组 arr 中存在三个下标 i、j、k 满足 arr[i]>arr[j]>arr[k] 且 arr[k]arr[j]arr[i]&#xff0c;则 arr[k]、arr[j] 和 arr[i] 三个元素组成一个斐波那契式子序列。由于数组 arr 严格递增&#xff0c;因此 arr[i]>arr[j]>arr[k] 等价于 i>j>k。 把这道题…

记录第一次使用air热更新golang项目

下载 go install github.com/cosmtrek/airlatest 下载时提示&#xff1a; module declares its path as: github.com/air-verse/air but was required as: github.com/cosmtrek/air 此时&#xff0c;需要在go.mod中加上这么一句&#xff1a; replace github.com/cosmtrek/air &…