【问题标题】:Why am i requiring to return again inside the higher order function为什么我需要在高阶函数中再次返回
【发布时间】:2019-07-17 15:37:45
【问题描述】:

一直在研究 python3 中的一些decorators。下面是一个代码sn-p。为什么我需要返回函数 (fn),当它在 wrapper 函数内部调用时

from functools import wraps

def log_function_data(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        print(fn.__name__)
        print(fn.__doc__)
        return fn(*args, **kwargs)   #why am i returning this?
    return wrapper

@log_function_data
def add(x,y):
    '''Adds 2 numbers and returns'''
    return x + y

add 函数已经在返回操作结果。所以我在没有decorator 的情况下调用添加函数,返回的工作方式如下:

def add(x,y):
    '''Adds 2 numbers and returns'''
    return x + y

result = add(2,3) ##have the result = 5

【问题讨论】:

  • 标记一个问题,没有 cmets 是一种耻辱!

标签: python-3.x python-decorators


【解决方案1】:

想象一下,您认识一个非常擅长数学的人。想象一下这个女孩,Alice,如此优秀,以至于她是世界上唯一能够解决问题X的人。

这里有个问题,Alice 只会说法语,但问题 X 可以用任何随机选择的语言来解释,并且预计也会用相同的语言来回答。可悲的是,她无法用法语以外的任何其他语言来解释问题 X。

假设您对解决问题 X 感兴趣。您考虑 2 分钟并得出一个解决方案:

我认识爱丽丝,她有数学部分,我认识伯纳德,他能 从任何语言翻译成法语并返回完美。让我们做 他们一起解决问题 X!

他们将使用的算法如下:

  1. 伯纳德阅读问题 X 并将其翻译成法语
  2. Alice 解决了法语版的 X
  3. 伯纳德将爱丽丝的答案翻译回原来的语言
  4. 返回解决方案

在python中是这样的:

def main():

  insane_translator = Bernard()

  def attach_translator(french_solver):

      def translation_decorator(X):
          french_X = insane_translator.translate(X, input_lang=X.lang, output="fr")
          french_solution = french_solver(french_X)
          solution = insane_translator.translate(french_solution, input_lang="fr", output=X.lang)
          return solution

      return translation_decorator

  x = X()
  solve = attach_translator(Alice.solve)
  solution = solve(x)
  print(solution)

class Alice:
    @staticmethod
    def solve(french_X):
        # Do some incredible things using french_X, Alice is a genius.
        return french_X + " 42"

class Bernard:
    def translate(self, text, input_lang=None, output=None):
        # Translate from any input language to any output language, Bernard is insane!
        return f"from {input_lang} to {output} of: \n\t{text}"

class X:
  def __init__(self):
    self.lang = "Alien"

  def __str__(self):
    return "\tProblem definition"


main()

伯纳德被用作翻译来“装饰”爱丽丝的工作能力。如果你不打电话给fn,那就意味着你没有让 Alice 工作,所以你只是来回翻译,没有任何好处。装饰器的目标是在调用被装饰函数之前和之后添加一些处理,重点是以与最初设计的方式不同的方式调用函数。

【讨论】:

    【解决方案2】:
        return fn(*args, **kwargs)  # why am i returning this?
    

    请咨询documentation。 Python 在不同的时间解释你的代码:

    1. 一次,在import 时间(当我们为函数生成字节码时)
    2. 在运行时(调用函数时)重复

    您可以选择不使用return fn,但这会导致生成的字节码发生重大变化,从而导致修饰函数返回默认值None。由于生成的字节码甚至不会调用add(),因此很难将最终结果称为“装饰”函数,它更像是一个完全不同的函数,忽略了传递给它的fn

    为了更好地理解装饰,您可能会发现使用dis 很有启发性。我建议对源代码进行一行更改,并注意变体字节码之间的差异。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-21
      • 2022-01-17
      • 1970-01-01
      • 2019-11-20
      • 1970-01-01
      • 2020-02-22
      • 1970-01-01
      相关资源
      最近更新 更多