python装饰器

Python 装饰器

装饰器(decorator)是 Python 中的一种高级功能,用于在不修改原函数代码的前提下,动态扩展函数或类的功能

本质上,装饰器是一个函数:它接收一个函数作为参数,并返回一个新的函数(通常是对原函数的增强版本)。

核心意思

不改原来函数里面的代码,就能给这个函数额外加新功能

装饰器通过 @decorator_name 语法应用在函数或方法定义之前。

Python 还提供了一些内置装饰器,例如 @staticmethod@classmethod

常见应用场景:

  • **日志记录:**记录函数调用信息、参数和返回值
  • **性能统计:**统计函数执行时间
  • **权限控制:**限制函数访问权限
  • **缓存:**缓存函数结果,提高性能

基本语法

装饰器的核心思想是:用一个函数"包装"另一个函数

py 复制代码
def decorator_function(original_function):
    def wrapper(*args, **kwargs):
        # 调用前
        print("执行前")

        result = original_function(*args, **kwargs)

        # 调用后
        print("执行后")

        return result
    return wrapper

@decorator_function
def target_function():
    print("原函数执行")

解析:

  • decorator_function:装饰器函数(接收原函数)

  • wrapper:包装函数(真正被执行)

  • @decorator_function:等价于函数替换

    target_function = decorator_function(target_function)

👉 调用 target_function() 时,实际上执行的是 wrapper()

复制代码
执行前
原函数执行
执行后

使用装饰器

装饰器通过 @ 语法糖应用在函数定义前:

py 复制代码
@time_logger
def target_function():
    pass

等价于

py 复制代码
def target_function():
    pass

target_function = time_logger(target_function)

这种机制使我们可以在不修改原函数的情况下,统一添加功能(如日志、权限等)。

py 复制代码
def my_decorator(func):
    def wrapper(): # 不是必须wrapper名字 可以是inner各种名字
        print("函数执行前")
        func()
        print("函数执行后")
    return wrapper

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

say_hello()
复制代码
函数执行前
Hello!
函数执行后
  • my_decorator 接收 say_hello
  • @my_decorator 替换原函数

带参数的装饰器

如果原函数有参数,需要在 wrapper 中使用 *args, **kwargs

py 复制代码
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("执行前")
        func(*args, **kwargs)
        print("执行后")
    return wrapper

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

greet("Alice")

**说明:**使用 *args, **kwargs 可以兼容任意参数函数。

py 复制代码
def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3) #循环三次
def say_hello():
    print("Hello!")

say_hello()
复制代码
Hello!
Hello!
Hello!

类装饰器

除了函数,装饰器也可以作用于类。

类装饰器接收一个类,并返回修改后的类或包装类。

  • 增强类方法
  • 控制实例化过程
  • 实现单例、日志等功能

函数形式的类装饰器

py 复制代码
def log_class(cls):
    class Wrapper:
        def __init__(self, *args, **kwargs):
            self.wrapped = cls(*args, **kwargs)

        def __getattr__(self, name):
            return getattr(self.wrapped, name)

        def display(self):
            print("调用前")
            self.wrapped.display()
            print("调用后")

    return Wrapper

@log_class
class MyClass:
    def display(self):
        print("原方法")

obj = MyClass()
obj.display()
复制代码
调用前
原方法
调用后

类形式的类装饰器

py 复制代码
class SingletonDecorator:
    def __init__(self, cls):
        self.cls = cls
        self.instance = None

    def __call__(self, *args, **kwargs):
        if self.instance is None:
            self.instance = self.cls(*args, **kwargs)
        return self.instance

@SingletonDecorator
class Database:
    def __init__(self):
        print("初始化")

db1 = Database()
db2 = Database()
print(db1 is db2)
复制代码
初始化
True

内置装饰器

常用内置装饰器:

  1. @staticmethod:定义静态方法,属于类,不属于对象
  2. @classmethod:定义类方法
  3. @property:将方法变为属性,把方法伪装成属性,调用不加括号
py 复制代码
class MyClass:
    @staticmethod
    def static_method():
        print("静态方法")

    @classmethod
    def class_method(cls):
        print(cls.__name__)

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

mycls = MyClass()
mycls.name = "111"
mycls.class_method()
print(mycls.name)

多个装饰器的堆叠

多个装饰器在定义阶段从下到上依次包裹函数调用阶段从上到下依次执行

py 复制代码
def decorator1(func):
    def wrapper():
        print("Decorator 1")
        func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("Decorator 2")
        func()
    return wrapper

@decorator1
@decorator2
def say_hello():
    print("Hello!")

say_hello()
复制代码
Decorator 1
Decorator 2
Hello!

装饰器 = 函数包装函数 + 不修改原代码扩展功能

相关推荐
浮生望2 小时前
React Router v7 实战全景:路由配置、嵌套路由、鉴权守卫与懒加载完整指南
前端
用户938515635072 小时前
从零在浏览器里跑 DeepSeek-R1:WebGPU + Transformer.js 全链路实战(二)
前端·javascript·typescript
(Charon)2 小时前
【C++】线程安全队列(二):生产者消费者模型与 condition_variable 阻塞等待
c语言·开发语言·c++
liwulin05062 小时前
【PYTHON】使用Selenium + ChromeDriver以及XPATH语法
开发语言·python·selenium
copyer_xyf2 小时前
Agentic RAG 实战:PostgreSQL + LangGraph 一条链路
python·postgresql·agent
JavaPub-rodert2 小时前
我又把自己的 Go 后台管理系统升级了一遍:文件管理、2GB 上传、私有文件预览、Docker 镜像全安排上了
开发语言·docker·golang·shiyuadmin
动力 continue3 小时前
Python 元类与异常类:类的“制造工厂”与“报错定制师”
开发语言·python·制造
quantdash_cc3 小时前
基于 QuantDash 5 分钟 K 线的网格交易策略参数网格搜索寻优实战
android·开发语言·pandas·量化·quantdash
雪隐3 小时前
个人电脑玩AI-16让5060 Ti给你打工——MiniMax H3 提速实录:从"泡杯茶等视频"到"视频等你",一张 5060 Ti 的自我修养
前端·人工智能·后端
147API3 小时前
Python批量生成蒸馏数据,并发、重试、幂等和断点续跑
开发语言·jvm·python