欢迎访问宙启技术站
智能推送

Python函数-装饰器的基本作用和语法

发布时间:2023-06-16 03:20:18

Python中函数装饰器是一种重要的编程机制,它们可以在不改变原函数的情况下修改其行为。本文将讲解函数装饰器的基本概念,以及如何使用它们来扩展函数功能。

一、基本概念

在Python中,函数是一种可调用对象,我们可以在函数中传递参数并得到返回值。但是,有时候我们需要对函数进行修改,比如增加日志记录、计时器、缓存等功能。传统的方式是直接修改原函数的代码,但这会让代码的可读性变差,而且很不灵活。

Python提供了一个更好的方式,就是使用函数装饰器。函数装饰器是一种语法糖,它可以在定义函数时对其进行修饰,并返回修饰后的函数。这个修饰过程在调用原函数时自动进行。例如:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print('Before the function is called.')
        result = func(*args, **kwargs)
        print('After the function is called.')
        return result
    return wrapper

@my_decorator
def my_function():
    print("The function is now runnung.")
    
my_function()

在上述例子中,我们定义了一个名为my_decorator的函数装饰器。它接受一个函数作为参数,并返回一个内部函数wrapper。这个内部函数会在原函数(这里是my_function)被调用前后添加额外的代码。最后,我们使用了装饰器语法@my_decorator来装饰了我们的函数my_function。当我们调用my_function()时,实际上是调用wrapper()函数,这个函数又会调用原函数my_function()并在前后添加了额外的输出语句。

二、常见应用

下面我们举例几种常见的函数装饰器:

1. 计时器

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print('Time elapsed:', end - start)
        return result
    return wrapper

@timer
def my_function():
    time.sleep(2)
    
my_function()
# 打印:Time elapsed: 2.0001866817474365

在这个例子中,我们定义了一个timer装饰器,它可以在原函数被调用前后记录时间,并输出一个时间消耗的估算。当我们用@timer装饰器装饰函数my_function时,它会计算出这个函数运行的时间。

2. 缓存

def cache(func):
    cached_results = {}
    def wrapper(*args, **kwargs):
        key = (args, tuple(kwargs.items()))
        if key not in cached_results:
            cached_results[key] = func(*args, **kwargs)
        return cached_results[key]
    return wrapper

@cache
def my_function(x, y):
    return x + y

my_function(1, 2) # 输出 3
my_function(1, 2) # 直接输出 3,不再调用原函数

这个例子定义了一个cache装饰器,它可以将函数的结果缓存起来以避免多余的计算。在下次调用这个函数时,它会直接返回之前的结果而不去调用原函数。这种方法在处理简单的计算型函数时很有效。

3. 登陆检查

def login_required(func):
    def wrapper(*args, **kwargs):
        if not is_logged_in():
            return redirect_to_login()
        else:
            return func(*args, **kwargs)
    return wrapper

@login_required
def my_function():
    pass

这个例子定义了一个login_required装饰器,它会检查用户是否已经登录。如果没有登录,则会重定向到登录页。如果已经登录,则会执行原函数。这种方法在处理网站应用程序时很常见。

三、注意事项

在使用函数装饰器时有一些注意事项:

1. 装饰器可以嵌套

一个装饰器可以由多个装饰器嵌套组成,每个装饰器都会依次修饰被装饰函数。例如:

@decorator1
@decorator2
def my_function():
    pass

这个例子中,my_function会先被decorator2装饰,然后再由decorator1装饰。

2. 装饰器会改变函数的元信息

因为装饰器本身就是一个函数,所以它可以通过调用functools.wraps来保留原函数的元信息,如下例:

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('Before the function is called.')
        result = func(*args, **kwargs)
        print('After the function is called.')
        return result
    return wrapper

@my_decorator
def my_function():
    """This is the docstring for my_function."""
    pass

print(my_function.__name__)        # 输出 my_function
print(my_function.__doc__)         # 输出 This is the docstring for my_function.

这个例子中,我们使用了functools.wraps来保留原函数的元信息,如函数名和文档字符串。如果不加这个保留操作,那么原函数的元信息会被覆盖掉。

3. 装饰器可以带参数

有时候我们需要在装饰器中传递一些参数,比如进行特定的配置。这可以通过在装饰器外再包一层函数来实现。例如:

def my_decorator_with_args(arg1, arg2):
    def my_decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print(f"Decorator arguments: {arg1} {arg2}")
            result = func(*args, **kwargs)
            print('After the function is called.')
            return result
        return wrapper
    return my_decorator

@my_decorator_with_args("hello", "world")
def my_function():
    pass

在这个例子中,我们在my_decorator_with_args装饰器外再包了一层函数来传递两个参数,并将其传递给装饰器内部的my_decorator函数使用。

四、总结

函数装饰器在Python编程中具有重要的作用,可以扩展函数的功能,并且使代码更加优雅和可读。它们的基本语法非常简单,可以通过定义内部函数并再包一层函数来实现。在使用函数装饰器时需要注意保留原函数的元信息,并了解装饰器的嵌套以及如何传递参数。