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.mzph.cn/pingmian/42571.shtml

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

相关文章

VSCode使用ipynb文件高效地进行功能测试

一、ipynb是什么文件 .ipynb文件是Jupyter Notebook的专用格式&#xff0c;它允许用户在一个网页应用中混合编写Markdown文本、执行代码、查看输出结果及图表。Jupyter Notebook的本质是一个Web应用程序&#xff0c;支持运行40多种编程语言&#xff0c;包括Python。它的主要用…

java反射介绍

Java反射API允许你在运行时检查和修改程序的行为。这意味着你可以动态地创建对象、查看类的字段、方法和构造函数&#xff0c;甚至调用它们。这是一个强大的特性&#xff0c;但也应该谨慎使用&#xff0c;因为它可以破坏封装性。 以下是使用Java反射的一些常见用途&#xff1a;…

403 Forbidden:深入解析 HTTP 禁止访问错误及排查方法

目录 一、理解 403 Forbidden 错误的本质 二、系统化排查 403 Forbidden 错误 三、常见的解决方法 四、错误详尽排查指南 步骤1&#xff1a;掌握基本知识 步骤2&#xff1a;确定错误范围 步骤3&#xff1a;检查显而易见的问题 步骤4&#xff1a;核对权限和访问控制 步…

【鸿蒙学习笔记】MVVM模式

官方文档&#xff1a;MVVM模式 [Q&A] 什么是MVVM ArkUI采取MVVM Model View ViewModel模式。 Model层&#xff1a;存储数据和相关逻辑的模型。View层&#xff1a;在ArkUI中通常是Component装饰组件渲染的UI。ViewModel层&#xff1a;在ArkUI中&#xff0c;ViewModel是…

[AHK V2]获取本地IP地址

问题&#xff1a;如何用AutoHotkey v2 获取本地IP地址。 解答&#xff1a;AutoHotkey v2 源代码如下 #Requires AutoHotkey v2; MsgBox GetLocalIPByAdapter(Ethernet) ; <— specify the adapter name you are interested in ; MsgBox GetLocalIPByAdapter(以太网) ; <…

《算法笔记》总结No.4——散列

散列的英文名是hash&#xff0c;即我们常说的哈希~该知识点在王道408考研的教材里面属于查找的范围。即便各位并无深入了解过&#xff0c;也听说过散列是一种更高效的查找方法。 一.引例 先来考虑如下一个假设&#xff1a;设有数组M和N分别如下&#xff1a; M[10][1,2,3,4,5,6…

ARM/Linux嵌入式面经(十三):紫光同芯嵌入式

static关键字 static关键字一文搞懂这个知识点,真的是喜欢考!!! stm32启动时如何配置栈的地址 在STM32启动时配置栈的地址是一个关键步骤,这通常是在启动文件(如startup_stm32fxxx.s,其中xxx代表具体的STM32型号)中完成的。 面试者回答: STM32启动时配置栈的地址主…

java IO流(1)

一. 文件类 java中提供了一个File类来表示一个文件或目录(文件夹),并提供了一些方法可以操作该文件 1. 文件类的常用方法 File(String pathname)构造方法,里面传一个路径名,用来表示一个文件boolean canRead()判断文件是否是可读文件boolean canWrite()判断文件是否是可写文…

早起能给我带来了什么

现在我早已养成习惯&#xff0c;每天不用闹钟也能自然醒来。有时5点起&#xff0c;有时4点半起&#xff0c;最早4点起&#xff0c;通常不晚于5点半。 相比在7点左右起床&#xff0c;我每天多出了2小时&#xff0c;按一天8小时工作时长计算&#xff0c;每年可以多出约90个工作日…

Spring懒加载Bean机制

一、概述 默认情况下Spring容器启动时就会创建被它管理的Bean&#xff0c;但是有的时候被Spring管理的Bean并不需要再容器启动的时候被创建&#xff0c;而是当对象第一次被访问的时候进行创建&#xff0c;这种场景就可以使用懒加载实现。 也就是说&#xff1a;容器启动的时候…

现场Live震撼!OmAgent框架强势开源!行业应用已全面开花

第一个提出自动驾驶并进行研发的公司是Google&#xff0c;巧的是&#xff0c;它发布的Transformer模型也为今天的大模型发展奠定了基础。 自动驾驶已经完成从概念到现实的华丽转变&#xff0c;彻底重塑了传统驾车方式&#xff0c;而大模型行业正在经历的&#xff0c;恰如自动驾…

基于S32K144驱动NSD8381

文章目录 1.前言2.芯片介绍2.1 芯片简介2.2 硬件特性2.3 软件特性 3.测试环境3.1 工具3.2 架构 4.软件驱动4.1 SPI4.2 CTRL引脚4.3 寄存器4.4 双极性步进电机驱动流程 5.测试情况6.参考资料 1.前言 最近有些做电磁阀和调光大灯的客户需要寻找国产的双极性步进电机驱动&#xf…

Android 15 应用适配默认全屏的行为变更(Android V的新特性)

简介 Android V 上默认会使用全面屏兼容方式&#xff0c;影响应用显示&#xff0c;导致应用内跟导航标题重合&#xff0c;无法点击上移的内容。 默认情况下&#xff0c;如果应用以 Android 15&#xff08;API 级别 35&#xff09;为目标平台&#xff0c;在搭载 Android 15 的设…

【SQLite3】常用API

SQLite3常用API 数据库的打开和关闭 数据库的打开&#xff08;sqlite3_open函数&#xff09; sqlite3_open() 函数用于打开一个 SQLite 数据库文件的函数&#xff0c;函数原型如下&#xff1a; int sqlite3_open(const char *filename, /* 数据库文件的文件名&#xff0c…

.net6+ 在单文件应用程序中获取程序集位置

一般来说,获取执行程序集的位置&#xff0c;您可以调用: var executableDirectory System.Reflection.Assembly.GetExecutingAssembly().Location;如果发布为单个文件, 会提示如下警告 warning IL3000: System.Reflection.Assembly.Location always returns an empty string…

解析Java中1000个常用类:EnumMap类,你学会了吗?

在线工具站 推荐一个程序员在线工具站&#xff1a;程序员常用工具&#xff08;http://cxytools.com&#xff09;&#xff0c;有时间戳、JSON格式化、文本对比、HASH生成、UUID生成等常用工具&#xff0c;效率加倍嘎嘎好用。 程序员资料站 推荐一个程序员编程资料站&#xff1a;…

python破解字母已知但大小写未知密码

python穷举已知字符串中某个或多个字符为大写的所有情况 可以使用递归函数来实现这个功能。以下是一个示例代码&#xff1a; def generate_uppercase_combinations(s, index0, current):if index len(s):print(current)returngenerate_uppercase_combinations(s, index 1, …

图神经网络dgl和torch-geometric安装

文章目录 搭建环境dgl的安装torch-geometric安装 在跑论文代码过程中&#xff0c;许多小伙伴们可能会遇到一些和我一样的问题&#xff0c;就是文章所需要的一些库的版本比较老&#xff0c;而新版的环境跑代码会报错&#xff0c;这就需要我们手动的下载whl格式的文件来安装相应的…

数字信号处理及MATLAB仿真(3)——量化的其他概念

上回书说到AD转换的两个步骤——量化与采样两个步骤。现在更加深入的去了解以下对应的概念。学无止境&#xff0c;要不断地努力才有好的收获。万丈高楼平地起&#xff0c;唯有打好基础&#xff0c;才能踏实前行。 不说了&#xff0c;今天咱们继续说说这两个步骤&#xff0c;首先…

cloudflare tunnels tcp

这里是官网的说明Cloudflare Tunnel Cloudflare Zero Trust docs 根据实际情况安装环境 tunnels除了http,https协议是直接暴露公网&#xff0c;tcp是类似ssh端口转发。 在需要内网穿透的局域网找一条机子部署代理 我这边是window cloudflared tunnel login #生成一个身份校…