Python:我们真的需要装饰器包装器吗? (重访)

时间:2019-06-19 19:35:21

标签: python wrapper python-decorators

有人问了similar question,但是OP将包装器与没有返回值的函数进行了比较,因此答案集中在该“故障”上。
我了解装饰器,以及为什么在阅读this article之后使用装饰器而不是子类。在这里,他们编写了以下示例,其中介绍了包装器的需求:

def uppercase_decorator(function):
    def wrapper():
        funct = function()
        make_uppercase = funct.upper()
        return make_uppercase

    return wrapper

但是,我可以这样写“同一件事”(我希望你说不是):

def uppercase_decorator(function): #previously 'function' was called 'message' but 'function' is clearer for comparison. 
    make_uppercase = function().upper
    return make_uppercase

这两个版本都可以应用于此fn,从而在调用salute()时产生相同的输出('HI ALL!'):

@uppercase_decorator
def salute():
    return 'Hi all!'

如果main fn返回一个随机字符串(感谢@wim提出建议),则可以注意到每次运行它时,没有包装器的字符串总是在运行sayGarbage()行时返回相同的内容:

def decorateIt(fn):
    toUpper = fn().upper  
    return toUpper  

def decorateW(fn):  
    def wrapper():  
        funct = fn()  
        toUpper = funct.upper()  
        return toUpper  
    return wrapper  

import random, string  

@decorateIt  
def sayGarbage():  
    return "".join(random.choice(string.ascii_lowercase) for i in range(6))  

sayGarbage()

为什么会这样?

1 个答案:

答案 0 :(得分:3)

让我们看看这里发生了什么:

def uppercase_decorator(message): 
    make_uppercase = func().upper
    return make_uppercase

@uppercase_decorator
def salute():
    return 'Hi all!'
  • 首先,定义uppercase_decorator
  • 第二,salute被定义。
  • 第三,uppercase_decorator被称为 ,将函数对象salute替换为第一个位置参数(message)。

在这一点上,代码将崩溃,因为func()被调用并且未在任何地方定义。如果它在您的Python REPL会话中有效,那么您必须早早在全局范围内使用func这个名称,因此该代码似乎只是巧合地起作用。

  

我们真的需要装饰器包装器吗?

不。可以按照您的建议,以更好的“无封闭”样式编写装饰器,但并非如此。如果要编写不带嵌套函数的装饰器,请尝试使用流行的库decorator.py来尝试。看起来像这样:

from decorator import decorator

@decorator
def uppercase_decorator(func, *args, **kwargs):
    result = func(*args, **kwargs)
    return result.upper()