【Python】一文弄懂Python中的@wraps

文摘   科技   2024-09-02 07:42   江苏  








01


引言





大家好,我是AI算法之道!


Python是我最喜欢的编程语言之一,它向来以其简单性、多功能性和可读性而闻名。


在Python编程中有各种各样的小技巧,在本文中,我们将深入探讨Python3中@wraps 的原理和用法,希望可以帮助到大家





02


函数的元数据

元数据指的是有关函数本身的数据。
def apple():  '''a function that prints apple'''  print('apple')
print(apple.__name__) # appleprint(apple.__doc__) # a function that prints apple
上述例子中包括函数名.__name__ 或函数的描述.__doc__(上面只展示了两个例子,其实还有更多)。




03


 装饰器如何工作?


装饰器用于改变函数的行为方式,而无需更改任何源代码。
def greet(name):    return 'hello ' + name
print(greet('tom')) # hello tom
上述代码中,我们有一个正常的问候函数greet(),我们来看看装饰器后的效果,如下:
def add_exclamation(func):    def wrapper(name):        return func(name) + '!'    return wrapper
@add_exclamationdef greet(name): return 'hello ' + name
print(greet('tom')) # hello tom!
我们在函数greet()的上方添加@add_exclamation,用 add_exclamation()来装饰 greet()。这里,add_exclamation是装饰器,greet 是被装饰者(被装饰的函数)。

请注意,greet() 函数的行为已被更改(输出现在多了一个 !)--我们完全没有编辑函数 greet() 的源代码。这就是装饰器的功劳。




04


 装饰器语法


我们来看下装饰器的语法:

def add_exclamation(func):    def wrapper(name):        return func(name) + '!'    return wrapper
@add_exclamationdef greet(name): return 'hello ' + name
print(greet('tom')) # hello tom!
上述装饰器的写法等同于以下写法:
def add_exclamation(func):    def wrapper(name):        return func(name) + '!'    return wrapper
def greet(name): return 'hello ' + name
greet = add_exclamation(greet)
print(greet('tom')) # hello tom!

请注意 greet = add_exclamation(greet) 透过这一行,大家可以看出装饰器的神奇之处。






05


装饰器会导致元数据丢失


接着我们来讲解上述两种写法对元数据的影响,首先是普通的函数如下:

# undecorateddef greet(name):  '''says hello to someone'''  return 'hello ' + name
print(greet.__name__) # greetprint(greet.__doc__) # says hello to someone

在这里,我们可以顺利打印出函数 greet() 的元数据。我们来看看带装饰器的函数,如下:

# decorateddef add_exclamation(func):    def wrapper(name):        return func(name) + '!'    return wrapper
@add_exclamationdef greet(name): '''says hello to someone''' return 'hello ' + name
print(greet.__name__) # wrapperprint(greet.__doc__) # None
上述例子中,在我们用add_exclamation修饰函数 greet 之后,请注意元数据发生了变化。__name__ 的输出变成了 "wrapper",而 __doc__变成了函数 wrapperdocstring
这是因为当我们装饰函数greet 时,我们实际上就是在做这件事:
greet = add_exclamation(greet)
通过上述语句,我们给函数greet 重新分配了 add_exclamation 返回的函数 - wrapper
这就是为什么当我们尝试打印greet.__name__greet.__doc__时,会打印出wrapper 的元数据。








06


@wraps防止元数据丢失


接着我们来看看装饰器@wraps的定义:
from functools import wraps
def add_exclamation(func): @wraps(func) def wrapper(name): return func(name) + '!' return wrapper
@add_exclamationdef greet(name): '''says hello to someone''' return 'hello ' + name
print(greet.__name__) # greetprint(greet.__doc__) # says hello to someone

大家需要注意,尽管我们使用了add_exclamation进行装饰,函数greet 的元数据恢复到了正常状态。


更具体地说,@wraps(something) something 的元数据覆盖了函数的元数据。这样就不会丢失原始函数的元数据。







07


总结


本文重点介绍了python中装饰器的@wraps的基本原理和用法用例,希望这些小技巧可以帮助到大家,提升大家的工作效率!



您学废了吗?






点击上方小卡片关注我




添加个人微信,进专属粉丝群!


AI算法之道
一个专注于深度学习、计算机视觉和自动驾驶感知算法的公众号,涵盖视觉CV、神经网络、模式识别等方面,包括相应的硬件和软件配置,以及开源项目等。
 最新文章