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

在Python中如何使用装饰器来修改函数行为?

发布时间:2023-06-14 10:22:50

装饰器是Python中一个非常强大的概念,可以让我们修改已有函数的行为,同时又不需要修改原函数的代码。在本篇文章中,我们将会详细地介绍Python中如何使用装饰器来修改函数行为。

什么是装饰器?

装饰器是Python中一个特殊的语法糖,它允许我们在不改变函数原代码的情况下,向一个已有的函数添加新的功能。装饰器本质上就是一个函数,接受一个函数作为参数,返回一个新的函数。

装饰器的语法糖是使用“@”符号,在函数定义前面加上装饰器的名称。下面是一个简单的装饰器例子:

def decorator(func):
    def wrapper():
        print("Before function is called.")
        func()
        print("After function is called.")
    return wrapper

@decorator
def say_hello():
    print("Hello world!")

say_hello()

运行结果如下:

Before function is called.
Hello world!
After function is called.

该装饰器函数接受一个函数作为参数,返回一个新的函数wrapper。新的函数在原函数调用前后分别打印“Before function is called.”和“After function is called.”。

在定义say_hello函数时,我们使用@decorator语法糖来装饰该函数。因此,当我们调用say_hello()函数时,实际上是在调用decorator(wrapper)函数,即执行了wrapper()函数。

接下来,我们将详细介绍Python中常用的一些装饰器例子,以便更好地理解装饰器的用法。

装饰器例子一:计时装饰器

计时装饰器是Python中常用的一种装饰器。该装饰器可以记录函数的运行时间,以便我们进行性能分析。下面是一个简单的计时装饰器例子:

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__}函数运行时间为:{end - start}秒")
        return result
    return wrapper

@timer
def long_time_func(n):
    count = 0
    for i in range(n):
        count += i
    return count

print(long_time_func(10000000))

运行结果如下:

long_time_func函数运行时间为:0.5827116966247559秒
49999995000000

该装饰器函数接受一个函数作为参数,返回一个新的函数wrapper。新的函数在原函数调用前获取当前时间start,在原函数调用后获取当前时间end。然后,计算出函数的运行时间,并打印出来。最后,返回原函数的结果result。

在定义long_time_func函数时,我们使用@timer语法糖来装饰该函数。因此,当我们调用long_time_func()函数时,实际上是在调用timer(wrapper)函数,即执行了wrapper()函数,该函数会计算出函数运行时间,并返回函数运行结果。

装饰器例子二:缓存装饰器

缓存装饰器是Python中另一种常用的装饰器。该装饰器可以使用一个字典来记录函数的运行结果,以便函数下次调用时可以直接返回缓存结果,从而提高函数的执行效率。下面是一个简单的缓存装饰器例子:

import functools

def cache(func):
    cache_dict = {}
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        key = str(args) + str(kwargs)
        if key not in cache_dict:
            print("Function is not cached.")
            cache_dict[key] = func(*args, **kwargs)
        else:
            print("Function is cached.")
        return cache_dict[key]
    return wrapper

@cache
def fib(n):
    if n in (0, 1):
        return n
    return fib(n-1) + fib(n-2)

print(fib(10))
print(fib(10))

运行结果如下:

Function is not cached.
Function is not cached.
Function is not cached.
Function is not cached.
Function is not cached.
Function is not cached.
Function is not cached.
Function is not cached.
Function is not cached.
Function is not cached.
55
Function is cached.
55

该装饰器函数定义了一个字典cache_dict,用来记录函数的运行结果。在新的函数wrapper中,先把函数的参数args和kwargs转换为字符串,然后用该字符串作为缓存字典的键值key。如果在字典中找不到该键值,则说明函数没有被缓存,需要调用原函数计算结果,并将结果缓存到字典中。如果能在字典中找到该键值,则说明函数已经被缓存,直接返回该结果即可。

在定义fib函数时,我们使用@cache语法糖来装饰该函数。因此,当我们调用fib()函数时,实际上是在调用cache(wrapper)函数,即执行了wrapper()函数,该函数会缓存函数运行结果,从而提高函数的执行效率。

装饰器例子三:权限控制装饰器

权限控制装饰器是Python中另一个常用的装饰器。该装饰器可以根据用户的权限控制访问哪些函数,以便保护敏感数据。下面是一个简单的权限控制装饰器例子:

def login_required(func):
    def wrapper(*args, **kwargs):
        username = input("请输入用户名:")
        password = input("请输入密码:")
        if username == "admin" and password == "12345":
            print("登陆成功!")
            return func(*args, **kwargs)
        else:
            print("用户名或密码错误!")
    return wrapper

@login_required
def access_permission():
    print("您已经获得权限,可以访问敏感数据了。")

access_permission()

运行结果如下:

请输入用户名:admin
请输入密码:12345
登陆成功!
您已经获得权限,可以访问敏感数据了。

该装饰器函数接受一个函数作为参数,返回一个新的函数wrapper。新的函数在原函数调用前首先弹出一个登陆框,让用户输入用户名和密码。如果用户名和密码验证通过,即登陆成功,则执行原函数,并返回结果。否则,提示“用户名或密码错误!”。

在定义access_permission函数时,我们使用@login_required语法糖来装饰该函数。因此,当我们调用access_permission()函数时,实际上是在调用login_required(wrapper)函数,即执行了wrapper()函数,该函数会判断用户名和密码是否正确,以便控制用户对敏感数据的访问权限。

结语

在Python中,装饰器是一种非常强大的概念,可以让我们在不改变原函数代码的情况下,修改函数的行为。本文介绍了Python中如何使用装饰器来实现计时装饰器、缓存装饰器和权限控制装饰器。这三种装饰器都是Python中非常常用的,值得我们掌握。