Python装饰器

1.什么是装饰器

装饰器是一个函数,这个函数的主要作用是包装另一个函数或类。
包装的目的是在不改变原函数名的情况下改变被包装对象的行为。
接收一个函数,内部对其包装,然后返回一个新函数,这样子动态的增强函数功能。
通过高阶函数传递函数参数,新函数添加旧函数的需求,然后执行旧函数。

2.什么时候使用装饰器

当你想为某个函数增加额外功能,而又不想在这个函数的源代码进行修改,就可以使用装饰器。

举例

假如现在我们有一个test函数:

def test(n:list):
    a = 0
    for i in range(n):
        a += i
    return a

现在我们想知道当n为1000000时,函数的执行时间,可以这样:

import time


def test(n:int):
    a = 0
    start = time.time()
    for i in range(n):
        a += i
    end = time.time()
    print('耗时:', end-start, '秒')
    return a


print(test(1000000))

结果为:



假如我们要多个函数都这样做,直接去修改函数就会很麻烦,这时候,我们就可以使用装饰器:

import time
from functools import wraps


def timethis(func):

    @wraps(func)
    def wrapper(*args, **wargs):
        start = time.time()
        result = func(*args, **wargs)
        end = time.time()
        print(func.__name__, '耗时:', end-start, '秒')
        return result

    return wrapper


@timethis
def test(n:int):
    a = 0
    for i in range(n):
        a += i
    return a


print(test(1000000))

结果:



可以看到,我们没有改变函数,只是在它上面加了一个@timethis,就拥有了计算时间的功能。这样,只要在需要计算时间的函数前加上这个装饰器就可以了,而不用依次去修改每个函数。

使用装饰器实现一个单例模式

def singleton(cls):
    instance = {}

    def wapper(*args, **kwargs):
        if cls not in instance:
            instance[cls] = cls(*args, **kwargs)
        return instance[cls]

    return wapper


@singleton
class User:

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


a1 = User('Tome')
a2 = User('Zhu')
print(a1 is a2)  #True

现在又有新的问题

你写了一个装饰器作用在某个函数上,但是这个函数的重要的元信息比如名字、文档字符串、注解和参数签名都丢失了。

解决方案

任何时候你定义装饰器的时候,都应该使用 functools 库中的 @wraps 装饰器来注解底层包装函数。

你可能感兴趣的:(Python装饰器)