Python装饰器

37 阅读2分钟

装饰器概述

装饰器允许在不修改原有函数代码的情况下给函数增加新的功能

装饰器本质上是一个函数,它可以接收一个函数作为参数并返回一个新的函数。这个新函数是对原函数的一种包装或增强,可以在不改变原函数代码的前提下,增加额外的功能。

def mydecorator(func):
    def wrapper(*args, **kwargs):
        print("Before calling the function")
        result = func(*args, **kwargs)
        print("After calling the function")
        return result+5
​
    return wrapper
​
@mydecorator
def my_function(x, y):
    return x+y
​
print(my_function(1, 2))

使用装饰器的步骤

定义装饰器:首先定义一个装饰器函数,该函数接收一个函数作为参数。

定义包装函数:在装饰器函数内部,定义一个包装函数(wrapper),这个包装函数会调用原函数,并可以在调用前后添加额外的逻辑。

返回包装函数:装饰器函数返回这个包装函数。

使用@语法:在需要被装饰的函数定义前使用@符号加上装饰器名称,这样Python解释器会自动将这个函数作为参数传递给装饰器,并将返回的新函数(包装函数)赋值给原函数名。

注意:带参数的装饰器,当被装饰的函数需要参数时,装饰器中的包装函数(wrapper)也需要能够接收这些参数。这通常通过*args**kwargs实现。

装饰器带参数

def mydecorator2(count):
    def mydecorator(func):
        def wrapper(*args, **kwargs):
            result = 0
            for i in range(count):
                print("Before calling the function")
                result += func(*args, **kwargs)
                result += 1
                print("After calling the function")
            return result
        return wrapper
    return mydecorator
​
@mydecorator2(3)
def my_function(x, y):
    return x+y
​
print(my_function(1, 2))

使用functools.wraps保留原函数信息

在使用装饰器时,原函数的元信息(如函数名、文档字符串等)会被包装函数所替代。为了保留这些信息,可以使用functools.wraps装饰器。

from functools import wraps
def mydecorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """function2"""
        print("Before calling the function")
        result = func(*args, **kwargs)
        print("After calling the function")
        return result+5
​
    return wrapper
​
@mydecorator
def my_function(x, y):
    """function1"""
    return x+y
​
print(my_function(1, 2))
print(my_function.__doc__)

args和kwargs

def demo(*args, **kwargs):
    print(args)
    print(kwargs)
​
gl_nums = (1, 2, 3)
gl_dict = {"name":"小明", "age":18}
​
demo(gl_nums, gl_dict)  # 把两个变量都传给了*args
demo(*gl_nums, **gl_dict)  # 拆包方式# 输出
((1, 2, 3), {'name': '小明', 'age': 18})
{}
(1, 2, 3)
{'name': '小明', 'age': 18}