Python 中的装饰器

22 阅读2分钟

zhuanlan.zhihu.com/p/127227990…

www.cnblogs.com/goldsunshin…

令人疑惑的装饰器

Python 里面测语法糖太多,装饰器是其中一个,用到了闭包的原理。
个人感觉最大测作用就是节省代码

最简单的例子

# 定义一个简单的装饰器
def simple_decorator(func):     # 传入一个函数作为参数
    # 包装原始函数的内部函数
    def wrapper():
        print("即将执行函数...")
        func()                  # 执行原始函数
        print("函数执行完毕。")
    return wrapper

# 使用装饰器
@simple_decorator
def greet():
    print("被修饰的函数:你好!")

# 调用被装饰的函数
greet()

例子1 不带参数的装饰器


import time
import random


def timer(func):
    def decorated(*args, **kwargs):
        st = time.time()
        ret = func(*args, **kwargs)
        print("time cost: {} seconds".format(time.time() - st))
        return ret
    return decorated



@timer
def random_sleep():
    time.sleep(random.randint(0,5))

random_sleep()
# >>> time cost: 2.0021181106567383 seconds

例子2 带参数的装饰器,相当于包了两层

def timer(print_args):
    def decorator(func):
        def wrapper(*args, **kwargs):
            st = time.time()
            ret = func(*args, **kwargs)
            if print_args:
                print(f"{func.__name__}, args: {args}, kwargs: {kwargs}")
            print("time cost: {} seconds".format(time.time() - st))
            return ret
        return wrapper
    return decorator


@timer(print_args=True)
def random_sleep():
    time.sleep(random.randint(0,5))

random_sleep()
# >>> random_sleep, args: (), kwargs: {}
# time cost: 9.34600830078125e-05 seconds

例子3 用类实现装饰器(函数替换)


class timer:

    def __init__(self, print_args):
        self.print_args = print_args

    def __call__(self, func):
        def decorator(*args, **kwargs):
            st = time.time()
            ret = func(*args, **kwargs)
            if self.print_args:
                print(f"{func.__name__}, args: {args}, kwargs: {kwargs}")
            print("time cost: {} seconds".format(time.time() - st))
            return ret
        return decorator


@timer(print_args=True)
def random_sleep():
    time.sleep(random.randint(0,5))

random_sleep()
>>> random_sleep, args: (), kwargs: {}
time cost: 5.004449367523193 seconds

例子4 用类实现装饰器(实例替换)

class DelayedStart:

    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        time.sleep(1)
        print("wait for 1 second")
        return self.func(*args, **kwargs)

    def eager_call(self, *args, **kwargs):
        print("call without delay")
        return self.func(*args, **kwargs)


# demo已经变成DelayedStart的一个实例,等同于 demo = DelayedStart()
@DelayedStart
def demo():
    print("hello world")


# 相当于调用__call__方法
# demo()

# 调用额外方法
# demo.eager_call()

装饰器的应用场景

通过上述分析,我们可以看到,装饰器似乎提供了一种动态修改或者说加强函数的能力,通过使用装饰器,你可以在原函数的基础上增加一些逻辑,最大的用处是节省代码。

那装饰器主要可以用在哪些场景呢

  1. 日志记录:在函数执行前后自动添加日志记录,方便调试和监控程序行为。
  2. 性能测试:装饰器可以用来测量函数的执行时间,帮助识别性能瓶颈。
  3. 权限验证:在Web开发中,装饰器可以用于检查用户是否有权访问某个资源或执行特定操作。
  4. 缓存(Memoization) :通过装饰器实现函数结果的缓存,避免重复计算相同的输入值,从而提高效率。