装饰器

装饰器

装饰器是给现有的模块或者函数增添新的小功能,可以对原函数进行功能扩展,而且还不需要修改原函数的内容,也不需要修改原函数的调用,总而言之,就是对原函数本身没有影响。

代码

#!/usr/bin/env python

from datetime import datetime

def log(func):
    def decorator(*args,**kwargs):
    	print("Function " + func.__name__ + " has been called at " + datetime.now().strftime("%Y-%m-%d %H:%M:%S") )
    	return func(*args,**kwargs)
    return decorator
    

@log
def add(a,b):
    return a + b

@log
def test():
    print("test")
    
a = add(2,3)
print(a)
test()

运行结果

┌──(root㉿kali)-[~/python_code/python_4]
└─# python decorate.py
Function add has been called at 2025-06-28 06:32:05
5
Function test has been called at 2025-06-28 06:32:05
test

详解装饰器(了解)

Python 装饰器(Decorator)是 Python 中一种强大的语法特性,它允许在不修改原函数或类代码的前提下,动态地扩展或修改其功能。装饰器的本质是一个 高阶函数,它接受一个函数或类作为参数,并返回一个新的函数或类,从而实现对原始对象的“包装”或“增强”。

一、装饰器的核心原理

1. 函数是一等对象

Python 中的函数是一等对象(First-Class Object),这意味着:

  • 函数可以作为参数传递给其他函数。
  • 函数可以作为其他函数的返回值。
  • 函数可以被赋值给变量。

2. 闭包(Closure)

装饰器的实现依赖于 闭包。闭包是指在一个函数内部定义的函数,并且该内部函数可以访问外部函数的变量。

3. 高阶函数

装饰器本质上是一个高阶函数,它接收一个函数作为参数,并返回一个新的函数。

二、装饰器的基本语法

1. 简单装饰器

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

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

say_hello()

输出:

函数执行前的操作
Hello!
函数执行后的操作

2. 语法糖 @ 的作用

  • @my_decorator 等价于 say_hello = my_decorator(say_hello)
  • Python 会自动将 say_hello 函数传递给 my_decorator,并用返回的 wrapper 替换原函数。

三、装饰器的实现原理

装饰器的核心思想是通过 闭包函数 包裹原始函数,并在其前后添加额外逻辑。以下是一个通用装饰器的模板:

def decorator(func):
    def wrapper(*args, **kwargs):
        # 执行前的逻辑
        result = func(*args, **kwargs)
        # 执行后的逻辑
        return result
    return wrapper

示例:记录函数执行时间

import time

def get_time(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"函数 {func.__name__} 执行耗时: {end - start:.6f} 秒")
        return result
    return wrapper

@get_time
def slow_function(n):
    sum(x for x in range(n))

slow_function(1000000)

四、装饰器的应用场景

1. 权限控制

def login_required(func):
    def wrapper(*args, **kwargs):
        user = "admin"  # 模拟登录状态
        if user == "admin":
            return func(*args, **kwargs)
        else:
            print("请先登录!")
    return wrapper

@login_required
def comment():
    print("发表评论")

comment()

2. 缓存(Memoization)

def memoize(func):
    cache = {}
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper

@memoize
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(50))  # 快速计算斐波那契数

3. 日志记录

def log(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数 {func.__name__},参数: {args}, {kwargs}")
        result = func(*args, **kwargs)
        print(f"函数 {func.__name__} 返回值: {result}")
        return result
    return wrapper

@log
def add(a, b):
    return a + b

add(3, 5)

五、装饰器的高级用法

1. 带参数的装饰器

装饰器本身也可以接收参数,需要再嵌套一层函数:

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

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

greet("Alice")

2. 类装饰器

装饰器不仅可以是函数,还可以是类(需实现 __call__ 方法):

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print(f"函数已被调用 {self.num_calls} 次")
        return self.func(*args, **kwargs)

@CountCalls
def example():
    print("执行示例函数")

example()
example()
example()

3. 保留原函数的元信息

使用 functools.wraps 保留原函数的名称和文档字符串:

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("装饰器逻辑")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def original_function():
    """这是一个原函数"""
    pass

print(original_function.__name__)  # 输出: original_function
print(original_function.__doc__)   # 输出: 这是一个原函数

六、装饰器的执行时机

  1. 装饰器定义时:装饰器函数在模块加载时立即执行。
  2. 装饰器调用时:装饰器返回的 wrapper 函数在目标函数被调用时执行。
def my_decorator(func):
    print("装饰器被定义时执行")
    def wrapper():
        print("装饰器逻辑执行")
        func()
    return wrapper

@my_decorator
def target():
    print("目标函数")

print("装饰器定义完成")
target()

输出:

装饰器被定义时执行
装饰器定义完成
装饰器逻辑执行
目标函数

七、内置装饰器速查表

装饰器 用途说明
@property 将方法伪装成属性访问(常用于只读属性)。
@classmethod 定义类方法,第一个参数是类本身(cls)。
@staticmethod 定义静态方法,无需 selfcls 参数。
@lru_cache 缓存函数结果(基于最近最少使用策略)。
@dataclass 自动生成数据类的 __init____repr__ 等方法。
@contextmanager 使用 with 语句实现上下文管理器。

八、总结

装饰器是 Python 中非常强大的工具,它能够显著提升代码的复用性和可维护性。通过装饰器,你可以:

  • 在不修改原始代码的情况下扩展功能。
  • 实现统一的日志记录、权限控制、性能分析等逻辑。
  • 提高代码的简洁性和可读性。

掌握装饰器后,你可以在实际开发中灵活应用它,比如构建 REST API 的路由、实现缓存机制、进行权限校验等。

posted on 2025-06-29 08:14  burgess0x  阅读(10)  评论(0)    收藏  举报