首页 > 解决方案 > Python:我们真的需要装饰器的包装器吗?(重访)

问题描述

已经提出了一个类似的问题,但是 OP 将包装器与没有返回的函数进行比较,因此答案集中在那个“错误”上。阅读本文
后,我了解了装饰器以及为什么我们使用它们而不是子类。在那里,他们编写了以下示例,其中介绍了包装器的需求:

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,在调用时产生相同的输出('HI ALL!')salute()

@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()

为什么呢?

标签: pythonwrapperpython-decorators

解决方案


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

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()

推荐阅读