当前位置: 首页 > news >正文

python装饰器的简单理解

python装饰器可分为函数装饰器和类装饰器,在理解过程中,可以认为是相同的。

一、不带参数的函数装饰器

def my_decorator(func):def wrapper():print("函数执行前")func()print("函数执行后")return wrapper

这里my_decorator就是我们定义的一个不带参数的装饰器(其本身就是一个函数),

使用如下:

@my_decorator
def say_hello():print("Hello!")

上述代码段可以简单的理解为say_hello=my_decorator(say_hello),即将say_hello函数作为参数传递给装饰器函数,并返回装饰器函数中定义的函数名。因此,say_hello=wrapper

当我们执行say_hello()时,相当于执行wrapper()
执行结果如下:

say_hello()输出:
复制函数执行前
Hello!
函数执行后

二、带参数的函数装饰器

定义带参数的函数装饰器

def repeat(num_times):def decorator(func):def wrapper(*args, **kwargs):for _ in range(num_times):result = func(*args, **kwargs)return resultreturn wrapperreturn decorator

使用如下:

@repeat(3)
def greet(name):print(f"Hello, {name}!")

这里,@repeat(3)相当于@decorator(可以简单的理解为,先将参数传递给外部装饰器repeat,然后返回真正的装饰器decorator)
因此 上述代码可以看做greet=decorator(greet)greet = wrapper 只是相比于不带参数的装饰器多传递了一个参数。

当我们执行greet()时,同样相当于执行wrapper()
执行实例如下:

greet("Alice")
输出:
Hello, Alice!
Hello, Alice!
Hello, Alice!

三、类装饰器

定义类装饰器

class MyDecorator:def __init__(self, func):self.func = funcdef __call__(self, *args, **kwargs):print("函数执行前")result = self.func(*args, **kwargs)print("函数执行后")return result

调用如下:

@MyDecorator
def say_hello():print("Hello!")

上述代码可以直接理解为say_hello = MyDecorator(say_hello) 因此,当使用say_hello()时,相当于直接调用__call__()函数

执行实例如下:

say_hello()输出:
函数执行前
Hello!
函数执行后

四、装饰器作用于类定义

定义装饰器:

def add_class_name(cls):# 在类上添加一个属性,并返回原类cls.class_name = 'person class'return cls

调用如下:

@add_class_name          
class Person:def __init__(self, name):self.name = name

上述代码可以等价于Person = add_class_name(Person),那么此时调用Person就相当于调用add_class_name(Person)

执行实例

A = Person()

上面这行代码相当于在运行A = add_class_name( Person)运行的结果,就是返回了一个被装饰过的新的cls,因此新的cls有了新的属性class_name,我们就可以调用 print(A.class_name) # 输出: "person class"

五、 装饰器的作用

个人理解:

  1. 增加代码复用:装饰器中封装一些通用的功能,定义不同函数时都可以利用装饰器中的功能。(固定装饰器,原函数不固定);
  2. 为原函数拓展功能:不改动原函数中的代码,例如:第一节中的say_hello()函数作为无法改动的原函数,那么我们可以通过改动装饰器中的功能,为原函数添加拓展功能(固定原函数,改动装饰器);

六、应用场景

Python 中装饰器的应用场景主要用于代码复用逻辑抽离横切关注点(如日志、验证、缓存、安全控制等)。下面是一些典型应用场景和具体示例:


6.1 日志记录(Logging)

用途:记录函数或方法的调用行为,便于调试和分析。

def log(func):def wrapper(*args, **kwargs):print(f"[LOG] Calling {func.__name__} with args={args}, kwargs={kwargs}")result = func(*args, **kwargs)print(f"[LOG] {func.__name__} returned {result}")return resultreturn wrapper@log
def add(a, b):return a + badd(2, 3)

6.2. 权限验证(Authentication/Authorization)

用途:用于 Web 应用、命令行工具中限制某些函数的访问。

def require_admin(func):def wrapper(user, *args, **kwargs):if not user.get("is_admin"):raise PermissionError("You must be an admin.")return func(user, *args, **kwargs)return wrapper@require_admin
def delete_user(user, user_id):print(f"Deleting user {user_id}")

6.3. 函数缓存(Memoization)

用途:缓存计算结果,加速函数响应,避免重复计算。

from functools import lru_cache@lru_cache(maxsize=128)
def fibonacci(n):if n < 2:return nreturn fibonacci(n - 1) + fibonacci(n - 2)print(fibonacci(40))  # 快速返回

6.4. 性能计时(Profiling)

用途:度量函数执行时间,用于性能分析。

import timedef timer(func):def wrapper(*args, **kwargs):start = time.time()res = func(*args, **kwargs)end = time.time()print(f"{func.__name__} took {end - start:.4f}s")return resreturn wrapper@timer
def slow_function():time.sleep(1)return "Done"slow_function()

6.5. 类注册与插件机制

用途:动态注册类或函数用于工厂、插件系统。

registry = {}def register(name):def decorator(cls):registry[name] = clsreturn clsreturn decorator@register("dog")
class Dog:def speak(self):return "Woof"print(registry["dog"]().speak())  # 输出 "Woof"

6.6. 输入验证 / 参数检查

用途:自动检查输入是否符合预期。

def validate_non_negative(func):def wrapper(x):if x < 0:raise ValueError("Negative value not allowed")return func(x)return wrapper@validate_non_negative
def sqrt(x):return x ** 0.5

6.7. 类装饰器(用于元编程、修改类行为)

用途:为类增加静态属性、方法、注册机制等。

def add_repr(cls):def __repr__(self):return f"{cls.__name__}({self.__dict__})"cls.__repr__ = __repr__return cls@add_repr
class Person:def __init__(self, name):self.name = nameprint(Person("Alice"))

相关文章:

  • 【深度剖析】三一重工的数字化转型(下篇1)
  • 基于SamOutV8的序列生成模型实现与分析
  • 用本地大模型解析智能家居语音指令:构建一个离线可用的文本控制助手
  • 保姆式一步一步制作B端左侧菜单栏
  • 状态码··
  • 从零开始构建一个区块链应用:技术解析与实践指南
  • 【Fargo】razor框架调用mediasoup的发送和接收能力
  • 英语写作中“随着……的出现”with the advent of 的用法
  • 线性代数中的向量与矩阵:AI大模型的数学基石
  • 内存越界(Memory Out-of-Bounds)详解
  • SGlang 推理模型优化(PD架构分离)
  • Linux Shell编程(九)
  • Android12 launcher3修改App图标白边问题
  • 如何利用夜莺监控对Redis Cluster集群状态及集群中节点进行监控及告警?
  • JVM学习(五)--执行引擎
  • Manus AI突破多语言手写识别的技术壁垒的关键方法
  • Docker:容器化技术
  • 数据库MySQL进阶
  • 论文阅读笔记——Emerging Properties in Unified Multimodal Pretraining
  • 通过shell脚本检测服务是否存活并进行邮件的通知
  • 网站建设一条龙/信阳seo推广
  • 武汉光谷做网站的公司/seo zac
  • 广州番禺疫情/百度seo按天计费
  • wordpress日志在哪个文件/关键词首页排名优化公司推荐
  • 网站架构模板/零基础学电脑培训班
  • 祝桥建设网站/百度投广告怎么收费