跳转至

Python 装饰器

约 297 个字 139 行代码 预计阅读时间 4 分钟

Info

好玩!

引入

在python中,函数也是一种对象,同样可以作为参数,甚至可以作为返回值。

Python
1
2
3
4
5
6
7
8
9
def square(x):
    return x*x

def print_running(f, x):
    print(f'{f.__name__:} is running')
    return f(x)

result = print_running(square, 5)
print(result)

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def get_multiple_func(n):
    def multiple(a):
        return a * n

    return multiple

double = get_multiple_func(2)
triple = get_multiple_func(3)

print(double(5))
print(triple(5))

decorator可以看作是一个传入值是函数、输出也是函数的函数。(虽然输出不一定是函数)

Decorator解释

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def decorator_function(original_function):
    def wrapper(*args, **kwargs):
        # 这里是在调用原始函数前添加的新功能
        before_call_code()

        result = original_function(*args, **kwargs)

        # 这里是在调用原始函数后添加的新功能
        after_call_code()

        return result
    return wrapper

# 使用装饰器
@decorator_function
def target_function(arg1, arg2):
    pass  # 原始函数的实现
Python
1
2
3
4
5
6
def decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)

        return result
    return wrapper
原有函数的功能

Python
1
2
3
4
5
6
7
def decorator(func):
    def wrapper(*args, **kwargs):
        print(f'{func.__name__} is running')
        result = func(*args, **kwargs)

        return result
    return wrapper
增加自己的功能。

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import time

def decorator(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f'Function {func.__name__} took {end - start} seconds')

        return result
    return wrapper
复杂一点的功能。

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import time

def decorator(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f'Function {func.__name__} took {end - start} seconds')

        return result
    return wrapper


def square(x):
    return x*x

decorate_square = decorator(square)
print(decorate_square(10))
使用装饰器。

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import time

def decorator(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f'Function {func.__name__} took {end - start} seconds')

        return result
    return wrapper


@decorator
def square(x):
    return x*x

print(square(10))
等价的。

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import time

def timer(threshold):
    def decorator(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()
            print(f'Function {func.__name__} took {end_time - start_time} seconds')
            if(end_time - start_time > threshold):
                print(f'Function {func.__name__} took more than {threshold} seconds')
            return result
        return wrapper
    return decorator

@timer(0.2)
def sleep_04():
    time.sleep(0.4)

sleep_04()
高级用法,装饰器生成器,根据传入的参数来生成装饰器。

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import time
import functools

def timer(threshold):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()
            print(f'Function {func.__name__} took {end_time - start_time} seconds')
            if(end_time - start_time > threshold):
                print(f'Function {func.__name__} took more than {threshold} seconds')
            return result
        return wrapper
    return decorator

@timer(0.2)
def sleep_04():
    time.sleep(0.4)

sleep_04()
这里又加了一个装饰器,将func的元数据传过去。

在 Python 中,装饰器是一种特殊的函数,用于“包装”另一个函数或方法,从而扩展或修改其功能。装饰器常用于:

  • 增加日志:记录函数的执行信息、参数、返回值等。
  • 计时:如代码中展示的,计算函数的执行时间。
  • 权限控制:在调用函数之前检查用户权限。
  • 缓存:缓存函数的计算结果,以提高性能。

装饰器通过 @decorator_name 的语法应用于函数,实际上是将装饰器函数返回的包装函数赋值给被装饰的函数。