【问题标题】:python decorator wraps twice?python装饰器包装两次?
【发布时间】:2020-12-01 20:14:48
【问题描述】:

偶然遇到python装饰器的一个奇怪问题,基本上我直接调用装饰器函数时,原来被包装的函数被包装了两次。

一些简单的代码来说明问题:

def my_deco(f):
    def wrapper(*args):
        print('some code before')
        f(*args)
        print('some code after')
    return wrapper

@my_deco
def original_func(text):
    print   (f'original func print {text}')

然后命令1):

original_func('hello')

将打印(顺便说一句,这是正确的):

some code before
original func print hello
some code after

但是命令2):

my_deco(original_func)('hello')

将在下面打印:

some code before
some code before
original func print hello
some code after
some code after

期望两个命令之间的结果相同,但后一个命令似乎将原始函数包装了两次。当我在不带括号的情况下运行这两个命令时,它们都正确地指向了包装函数,但是一旦使用括号执行,结果就会不同。

我有点说服自己有以下逻辑,但仍然感到不舒服,所以我正在寻找 cmet 或纠正我的想法:

命令1):调用 original_func -> my_deco -> wrapper -> wrapping + original_func 执行

命令2):调用my_deco -> wrapper -> wrapping + original_func 执行(是wrapped版本)

所以看起来命令 1) 中的 original_func 仍然是“原始”,没有包装;并且命令 2) 中的 original_func 是“包装”版本。

提前致谢。

【问题讨论】:

  • 嗯...是的。你把它包了两次。为什么要两次应用装饰器?
  • 这是无意的,显然只是一次。
  • 那是因为运行my_deco(original_func)('hello') 调用了装饰器,而不是再次调用装饰器(因为 original_func 被 my_deco 包装)然后是原始 func。

标签: python python-decorators


【解决方案1】:

当你定义 original_func 时,你使用了一个装饰器,所以 python 包装了它。在命令 2) 中,您自己再次包装了它,因此结果是函数被包装了两次。
如果您运行以下内容,则输出应该是正确的:

def original_func(text):
    print   (f'original func print {text}')

my_deco(original_func)('hello')

【讨论】:

  • 是的,您推荐的代码可以正常工作。但是我仍然很困惑为什么我的两个案例不同,正如我所说,当运行两个不带括号的命令时,它们都指向相同的包装函数,然后我应该期望相同的结果,但它不一样。
  • 你怎么知道它们指向同一个包装函数?您是否使用 te is 运算符比较了它们?
  • @jaydrill:你了解闭包了吗?两个函数都显示为 wrapper 的事实并不意味着它们是同一个函数。
  • 你们两个(Monica 和 Roy)都提供了帮助,这两个命令使用 'is' 运算符不同,并且闭包也不同。谢谢!
猜你喜欢
  • 2021-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
  • 2018-03-07
相关资源
最近更新 更多