Python装饰器用法介绍

P8QAD 数码 4

本文主要介绍Python装饰器的使用方法及其功能。在Python编程中,装饰器是一项非常强大的功能,可以节省代码,同时可以实现多种目的。我们将从以下几个方面对Python装饰器进行详细的阐述。

1、装饰器是什么

装饰器是Python函数的一个重要概念。可以理解为在一个函数外部添加另一个函数,以对原函数进行一些修改或增强功能。装饰器常常用于日志打印、性能测试、授权验证、缓存等场景。

2、装饰器的基本用法

装饰器通常以@符号表示,在函数定义前使用。如下所示:

    @decorator
    def func_name():
        pass

其中,decorator为装饰器函数名,func_name是待装饰的函数名。在函数运行时,装饰器会先于函数执行。

下面是一个简单的装饰器示例,用于输出函数执行时间:

    import time
    def time_cal(func):
        def wrapper():
            start_time = time.time()
            func()
            end_time = time.time()
            print("花费时间:", end_time - start_time, "秒")
        return wrapper
        
    @time_cal
    def hello():
        print("Hello world!")

上述代码中,time_cal是计时装饰器函数,wrapper函数记录函数开始和结束时间,hello为待装饰的函数。在@time_cal下,调用hello函数时,会先运行wrapper函数,记录执行时间,接着调用hello函数输出”Hello world!”。

缓存装饰器可以缓存函数的结果,以便在下次调用时直接获取,而不必重新执行函数。这对于复杂且耗时的函数尤其有用。下面是一个例子:

    import functools
    def cache(func):
        cached = functools.lru_cache(maxsize=None)
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            return cached(*args, **kwargs)
        return wrapper

    @cache
    def fib(n):
        if n < 2:
            return n
        return fib(n-1) + fib(n-2)

上述代码中,cache为缓存装饰器函数,使用了functools模块的lru_cache方法。在调用fib函数时,如果已经计算过fib(n)的值,则直接从缓存中获取;否则,执行fib(n)并将结果缓存起来。

日志装饰器可以用于记录函数的执行情况,比如输入参数、输出结果以及程序错误等。下面是一个简单的日志装饰器:

    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print(f"[INFO]: {func.__name__} start")
            result = func(*args, **kwargs)
            print(f"[INFO]: {func.__name__} end")
            return result
        return wrapper

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

在使用@log装饰器后,执行add函数时,会先打印函数名称和执行开始时间,接着输出函数结果,并打印执行结束时间。

装饰器函数可以被替换成一个装饰器类,使其具有更多的灵活性和可配置性。下面是一个装饰器类的例子:

    class Cache:
        def __init__(self, func):
            self.func = func
            self.cache = {}
            
        def __call__(self, *args):
            if args in self.cache:
                return self.cache[args]
            else:
                result = self.func(*args)
                self.cache[args] = result
                return result

    @Cache
    def fib(n):
        if n < 2:
            return n
        return fib(n-1) + fib(n-2)

上述代码中,Cache类实现了一个简单的缓存装饰器,和上一篇缓存装饰器不同之处在于函数被封装在类里面,而不是在函数内。

在Python中,可以同时使用多个装饰器对函数进行修饰。装饰器的执行顺序与装饰器定义顺序相反。下面是一个双重装饰器:

    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print(f"[INFO]: {func.__name__} start")
            result = func(*args, **kwargs)
            print(f"[INFO]: {func.__name__} end")
            return result
        return wrapper

    def cache(func):
        @functools.lru_cache(maxsize=None)
        @log
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper

    @cache
    def fib(n):
        if n < 2:
            return n
        return fib(n-1) + fib(n-2)

上述代码中,cache装饰器使用了另一个装饰器log,在每次函数执行前打印日志信息。

装饰器会改变函数的调用方式,比如参数列表、返回值类型等。为了不影响函数使用,需要在装饰器中添加functools.wraps(func)语句,保留原函数的元信息。否则,在调用help()等函数时,可能会显示错误的函数签名。

Python支持装饰器嵌套,即装饰器可以使用其他装饰器,实现更多的功能。但是,装饰器嵌套深度不能过大,否则会导致代码可读性下降和调试难度增加。

对于不需要修改原函数的装饰器,也可以不添加括号。比如在使用flask框架时,@app.route可以不加括号,直接使用。

本文主要介绍了Python装饰器的定义、基本用法、应用场景和高级用法,以及注意事项。装饰器是Python中非常强大的功能,帮助我们实现多种任务,如缓存、日志、性能等。虽然装饰器在使用上比较灵活,但需要我们在实践中多加练习,才能充分发挥它的优势。

回复

共1条回复 我来回复
  • 暂无回复内容