长亭百川云 - 文章详情

Python 中的 @wraps 到底是个啥东西?

未闻Code

85

2024-07-13

只要你读得很快

你可能在随意的 Python 代码中见过这个 @wraps 的东西,你可能想知道这到底是什么?

函数有元数据

元数据指的是函数本身的数据。

def apple():  
  '''a function that prints apple'''  
  print('apple')  
  
print(apple.__name__)  # apple  
print(apple.__doc__)   # 打印apple的函数  

例子包括函数名 .__name__ 或函数 docstring .__doc__

装饰器如何工作

装饰器用于改变函数的行为方式,而无需修改任何源代码。

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_exclamation  
def greet(name):  
    return 'hello ' + name  
  
print(greet('tom'))  # hello tom!  

我们通过在 greet() 上添加 @add_exclamation 来用 add_exclamation() 来装饰 greet()。这里,add_exclamation 是装饰器,greet 是被装饰的函数。

请注意,greet() 的行为已经改变,而我们根本没有编辑 greet() 的源代码。这是装饰器的功劳。

装饰语法魔术

def add_exclamation(func):  
    def wrapper(name):  
        return func(name) + '!'  
    return wrapper  
  
@add_exclamation  
def 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) ”一行。

装饰会导致元数据丢失

# 没有装饰  
def greet(name):  
  '''says hello to someone'''  
  return 'hello ' + name  
  
print(greet.__name__)  # greet  
print(greet.__doc__)   # says hello to someone  

在这里,我们可以顺利打印 greet() 的元数据

# 加了装饰  
def add_exclamation(func):  
    def wrapper(name):  
        return func(name) + '!'  
    return wrapper  
  
@add_exclamation  
def greet(name):  
  '''says hello to someone'''  
  return 'hello ' + name  
  
print(greet.__name__)  # wrapper  
print(greet.__doc__)   # None  

add_exclamation 装饰 greet 后,请注意元数据发生了变化。__name__ 变成了 “wrapper”,而 __doc__ 变成了 wrapper 的 docstring。

这是因为当我们装饰 greet 时,我们实际上是在做这件事:

greet = add_exclamation(greet)  

我们正在将 greet 重新分配给一个由 add_exclamation 返回的函数--wrapper

这就是为什么当我们尝试打印 greet.__name__greet.__doc__ 时,会打印 wrapper 的元数据的原因。

@wraps 防止元数据在装饰过程中丢失

from functools import wraps  
  
def add_exclamation(func):  
    @wraps(func)  
    def wrapper(name):  
        return func(name) + '!'  
    return wrapper  
  
@add_exclamation  
def greet(name):  
  '''says hello to someone'''  
  return 'hello ' + name  
  
print(greet.__name__)  # greet  
print(greet.__doc__)   # says hello to someone  

请注意,尽管使用了 ad_exclamation 装饰,greet 的元数据还是回到了正常状态。

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

更多每日开发小技巧

尽在****未闻 Code Telegram Channel !

END

未闻 Code·知识星球开放啦!

一对一答疑爬虫相关问题

职业生涯咨询

面试经验分享

每周直播分享

......

未闻 Code·知识星球期待与你相见~

一二线大厂在职员工

十多年码龄的编程老鸟

国内外高校在读学生

中小学刚刚入门的新人

在“未闻 Code技术交流群”等你来!

入群方式:添加微信“mekingname”,备注“粉丝群”(谢绝广告党,非诚勿扰!)

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备2024055124号-2