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

Python函数-装饰器:如何在函数前后添加额外功能

发布时间:2023-06-04 13:42:11

Python函数允许通过装饰器(Decorator)在函数前后添加额外的功能,这是 Python 中一个强大且常用的特性。它可以帮助程序员轻松实现常规任务,使代码更加直观、简洁和易于维护。

装饰器是 Python 中一种用来修改其他函数的函数,它定义了一些额外的逻辑代码,并将其绑定到待修饰函数上。它为函数提供了一种非侵入式的修改方法,所以不必直接修改函数的源代码,而是在运行时通过装饰器添加额外的功能。

Python中的装饰器有很多种,下面将介绍其中最常用的几种。

1. 装饰器定义

在Python中,装饰器是以@符号开头的特殊语法。 当 Python 解释器在函数定义时看到@my_decorator 时,它会自动将函数 my_function 作为参数传递给 my_decorator 函数,并将返回值(另一个函数)重新绑定到 my_function 变量上。

@my_decorator

def my_function():

    pass

等价于

def my_function():

    pass

my_function = my_decorator(my_function)

2. 装饰器示例

下面我们来看一个实际的例子,这个装饰器可以在函数执行前后记录函数的执行时间。

import time

def time_it(func):

    def wrapper(*args, **kwargs):

        start = time.time()

        result = func(*args, **kwargs)

        end = time.time()

        print(func.__name__ + " takes " + str((end-start)*1000) + "ms")

        return result

    return wrapper

@time_it

def my_func():

    time.sleep(1)

    print("Done")

my_func()

输出结果为:

Done

my_func takes 1000.7638931274414ms

可以看到,my_func() 被修饰器 time_it 包装了起来,函数执行时间被打印出来。

装饰器的作用就体现在能够在函数前后添加新的功能,而不会影响原函数的功能。

3. 带参数的装饰器

装饰器函数可以带不定个数和类型的参数,这样它就可以接收定制不同行为的配置参数。下面我们来看一个带参数的装饰器实例。

def repeat(number=3):

    def decorator(func):

        def wrapper(*args, **kwargs):

            for i in range(number):

                result = func(*args, **kwargs)

            return result

        return wrapper

    return decorator

@repeat(number=4)

def greet(name):

    print(f"Hello {name}")

greet("John")

输出结果为:

Hello John

Hello John

Hello John

Hello John

可以看到,函数 greet 被装饰器 repeat 包装了四次,实现了重复输出的功能。

4. 类装饰器

除了函数外,Python还支持类装饰器,类装饰器在修饰类时,将该类的构造函数作为参数交给被装饰器函数。

下面是一个类装饰器的实际例子,它可以为类的所有方法添加日志。

class LogDecorator:

    def __init__(self, obj):

        self.obj = obj

    

    def __call__(self, *args, **kwargs):

        for name, method in self.obj.__dict__.items():

            if callable(method):

                setattr(self.obj, name, self.__log_decorator(method))

        return self.obj

    

    @staticmethod

    def __log_decorator(method):

        def wrapped(*args, **kwargs):

            print(f"Enter into method '{method.__name__}'", args, kwargs)

            result = method(*args, **kwargs)

            print(f"Exit from method '{method.__name__}'", args, kwargs, result)

            return result

        return wrapped

@LogDecorator

class Calculator:

    def add(self, a, b):

        return a + b

    

    def sub(self, a, b):

        return a - b

c = Calculator()

print(c.add(1, 2))

print(c.sub(2, 1))

输出结果为:

Enter into method 'add' (1, 2) {}

Exit from method 'add' (1, 2) {} 3

3

Enter into method 'sub' (2, 1) {}

Exit from method 'sub' (2, 1) {} 1

1

可以看到,当我们在定义类 Calculator 时,在其前面加上装饰器 @LogDecorator,就可以为其所有方法添加了日志。

总结

装饰器是 Python 中一个非常重要且实用的特性,它可以避免代码的混乱,使代码更加直观、简洁和易于维护。通过装饰器,我们可以在函数前后添加新的功能,不必修改函数的源代码。 Python 提供了很多种装饰器的实现方法,其中最常用的有带参数的函数装饰器、类装饰器等。 在使用装饰器时,需要注意遵循一些 实践,如不改变函数签名等。