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

上一篇 / 下一篇  2024-07-15 11:45:57

  只要你读得很快
  你可能在随意的 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 的元数据覆盖了函数的元数据。这样,我们原来函数的元数据就不会丢失了。

TAG: 软件开发 Python

 

评分:0

我来说两句

Open Toolbar