python 装饰器功能与用法案例详解

1. 什么是装饰器

在介绍 python 装饰器的功能与用法案例详解前,我们首先需要了解什么是装饰器。在编程中,装饰器是一种函数或类,它允许我们在代码运行时动态地修改、扩展或包装其他函数、类或方法的行为。相当于在原有的代码结构上进行了装饰,为函数或类添加了额外的功能。

如下是一个简单的例子,定义了一个被装饰的函数,对其进行了装饰器的操作:

def my_decorator(func):

def wrapper():

print("Something is happening before the function is called.")

func()

print("Something is happening after the function is called.")

return wrapper

def say_hello():

print("Hello!")

say_hello = my_decorator(say_hello)

say_hello()

在这个例子中,我们先定义了一个装饰器函数 my_decorator。这个函数接受一个函数作为参数,然后返回另一个函数 wrapper,并在 wrapper 中添加了一些额外的代码,最后返回 wrapper

我们再定义了一个函数 say_hello,并把它传递给 my_decorator 函数,然后把返回的函数重新赋值给 say_hello。最后调用 say_hello 函数,此时实际上调用的是 wrapper 函数。

由此可见,装饰器实质上就是一个对原有函数或类的包装,它允许我们在不改变原有代码结构的情况下修改其行为。

2. 装饰器的语法

2.1 函数装饰器

下面我们来看看装饰器的语法。

函数装饰器的语法如下:

@decorator

def func():

pass

其中,decorator 是装饰器函数,它接受一个函数作为参数,然后返回另一个函数。

例如,我们可以使用下面的装饰器函数来对函数的执行时间进行计时:

import time

def my_timer(func):

def wrapper():

start_time = time.time()

func()

end_time = time.time()

print("Time used:", end_time - start_time)

return wrapper

@my_timer

def say_hello():

time.sleep(1)

print("Hello!")

say_hello()

在这个例子中,我们定义了一个装饰器函数 my_timer,它接受一个函数作为参数,然后返回另一个函数 wrapper。在 wrapper 中记录了函数执行前后的时间,并打印出执行时间。

然后我们使用 @my_timer 来装饰函数 say_hello,相当于执行了下面的语句:say_hello = my_timer(say_hello)

当我们调用 say_hello 函数时,会先执行 my_timer 函数,并返回 wrapper,然后再执行 wrapper 函数,最终打印出执行时间。

2.2 类装饰器

除了函数装饰器外,还可以使用类装饰器,它是一个类,接受一个函数作为参数,然后提供了一些额外的功能。

例如,我们可以使用下面的类装饰器来对函数进行缓存:

class Cache:

def __init__(self, func):

self.func = func

self.cache = {}

def __call__(self, *args):

if args in self.cache:

return self.cache[args]

else:

result = self.func(*args)

self.cache[args] = result

return result

@Cache

def fibonacci(n):

if n in (0, 1):

return n

else:

return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))

在这个例子中,我们定义了一个类装饰器 Cache,它接受一个函数作为参数,并提供了一个 __call__ 方法来代替原来的函数。在 __call__ 中,它先检查缓存中是否已经存在相同参数的计算结果,如果存在,则直接返回缓存中的结果,否则计算结果,并将结果存入缓存中。

我们使用 @Cache 来装饰函数 fibonacci,相当于执行了下面的语句:fibonacci = Cache(fibonacci)

当我们调用 fibonacci 函数时,会先执行 Cache 类的 __init__ 方法,并保存被装饰的函数和一个空缓存。然后再执行 fibonacci 函数,实际上是执行了 Cache 类的 __call__ 方法,并返回计算结果。

3. 装饰器的应用

3.1 函数调试

函数调试是编写代码时必不可少的一部分,当我们运行一个程序时,总会遇到一些错误,此时就需要进行调试。

下面是一个使用装饰器来进行函数调试的例子:

def debug(func):

def wrapper(*args, **kwargs):

print("Calling function:", func.__name__)

print("Args:", args)

print("Kwargs:", kwargs)

result = func(*args, **kwargs)

print("Result:", result)

return result

return wrapper

@debug

def add(x, y):

return x + y

add(2, 3)

在这个例子中,我们定义了一个装饰器函数 debug,它接受一个函数作为参数,并返回另一个函数 wrapper。在 wrapper 中,它先打印出函数名、参数以及关键字参数,然后执行函数,并打印出结果。

我们使用 @debug 来装饰函数 add,相当于执行了下面的语句:add = debug(add)

当我们调用 add 函数时,会先执行 wrapper 函数,并打印出函数名、参数以及关键字参数,然后再执行原有的 add 函数,最后打印出结果。

3.2 缓存函数计算结果

有些函数的计算结果是比较耗时的,例如递归计算斐波那契数列。如果经常调用这个函数,并且参数较大,那么计算时间将会非常长。

我们可以使用装饰器来对函数进行缓存,如果传入相同的参数,则直接返回缓存中的结果,这样可以显著提高函数的执行效率。

下面是一个使用装饰器来缓存函数计算结果的例子:

class Memoize:

def __init__(self, func):

self.func = func

self.cache = {}

def __call__(self, *args):

if args in self.cache:

return self.cache[args]

else:

result = self.func(*args)

self.cache[args] = result

return result

@Memoize

def fibonacci(n):

if n in (0, 1):

return n

else:

return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))

在这个例子中,我们定义了一个类装饰器 Memoize,它接受一个函数作为参数,并提供了一个 __call__ 方法来代替原来的函数。在 __call__ 中,它先检查缓存中是否已经存在相同参数的计算结果,如果存在,则直接返回缓存中的结果,否则计算结果,并将结果存入缓存中。

我们使用 @Memoize 来装饰函数 fibonacci,相当于执行了下面的语句:fibonacci = Memoize(fibonacci)

当我们调用 fibonacci 函数时,会先执行 Memoize 类的 __init__ 方法,并保存被装饰的函数和一个空缓存。然后再执行 fibonacci 函数,实际上是执行了 Memoize 类的 __call__ 方法,并返回计算结果。

3.3 函数授权

在一些情况下,有些人可能并不具备调用某个函数的权限,此时我们可以使用装饰器来授权。

下面是一个使用装饰器来授权的例子:

def check_permission(permission):

def decorator(func):

def wrapper(*args, **kwargs):

if permission == "admin":

return func(*args, **kwargs)

else:

raise ValueError("Permission denied")

return wrapper

return decorator

@check_permission("admin")

def add_user(username):

print("Adding user:", username)

add_user("Alice")

在这个例子中,我们定义了一个装饰器函数 check_permission,它接受一个参数 permission,返回一个装饰器函数,这个装饰器函数接受一个函数作为参数,并返回另一个函数 wrapper。在 wrapper 中,它首先检查传入的 permission 是否为 "admin",如果是,则执行原有的函数 func,否则抛出异常。

我们使用 @check_permission("admin") 来装饰函数 add_user,相当于执行了下面的语句:add_user = check_permission("admin")(add_user)

当我们调用 add_user 函数时,会先执行 check_permission("admin") 函数,返回一个装饰器函数,并将其应用于 add_user 函数上。

最终,当我们调用 add_user 函数时,会先执行 wrapper 函数,检查权限,然后再执行原有的 add_user 函数。

4. 总结

装饰器是 Python 中非常强大的语法,它允许我们在不改变原有代码结构的情况下,为函数或类添加额外的功能。本文介绍了装饰器的语法和几种常见的应用,例如函数调试、缓存函数计算结果、函数授权等。通过学习本文,相信读者已经对装饰器有了更加深入的了解,并可以利用装饰器来更好地编写 Python 代码。

免责声明:本文来自互联网,本站所有信息(包括但不限于文字、视频、音频、数据及图表),不保证该信息的准确性、真实性、完整性、有效性、及时性、原创性等,版权归属于原作者,如无意侵犯媒体或个人知识产权,请来电或致函告之,本站将在第一时间处理。猿码集站发布此文目的在于促进信息交流,此文观点与本站立场无关,不承担任何责任。

后端开发标签