Python 装饰器和装饰器模式有啥区别?

Posted

技术标签:

【中文标题】Python 装饰器和装饰器模式有啥区别?【英文标题】:What is the difference between Python decorators and the decorator pattern?Python 装饰器和装饰器模式有什么区别? 【发布时间】:2012-01-09 20:36:50 【问题描述】:

“Python 装饰器”和“装饰器模式”有什么区别?

什么时候应该使用 Python 装饰器,什么时候应该使用装饰器模式?

我正在寻找 Python 装饰器的示例以及实现相同功能的装饰器模式。

@AcceptedAnswer

我知道Jakob Bowyer's answer 是有效的。然而,是 Srikar 的回答让我明白了原因。

在 Srikar 的回答和研究给定的资源之后,我编写了这个示例,以便我可以可视化和理解 Python 装饰器和装饰器模式。

我必须不同意 Srikar 的“Python 装饰器不是装饰器模式的实现”。根据我的了解,我坚信 Python 装饰器是装饰器模式的一种实现。只是不是以经典方式。

另外,我需要补充一点,尽管 Srikar 说过“Python 装饰器在定义时为函数和方法添加功能”,你可以在运行时轻松使用 Python 装饰器

不过,我仍然将 Srikar 的回答标记为已接受,因为它帮助我理解了the implementationPython 中的装饰器模式

"""
Testing Python decorators against the decorator pattern
"""
def function(string):
    return string

def decorator(wrapped):
    def wrap(string):
        # Assume that this is something useful
        return wrapped(string.upper())
    return wrap

def method_decorator(wrapped):
    def wrap(instance, string):
        # Assume that this is something useful
        return wrapped(instance, string.upper())
    return wrap

@decorator
def decorated_function(string):
    print('! '.join(string.split(' ')))

class Class(object):
    def __init__(self):
        pass
    def something_useful(self, string):
        return string

class Decorator(object):
    def __init__(self, wrapped):
        self.wrapped = wrapped
    def something_useful(self, string):
        string = '! '.join(string.split(' '))
        return self.wrapped().something_useful(string)

    @method_decorator
    def decorated_and_useful(self,string):
        return self.something_useful(string)


if __name__ == '__main__':
    string = 'Lorem ipsum dolor sit amet.'
    print(function(string))                  # Plain function
    print(decorator(function)(string))       # Python decorator at run time
    print(decorated_function(string))        # Python decorator at definition time
    a = Class()
    print(a.something_useful(string))        # Plain method
    b = Decorator(Class)
    print(b.something_useful(string))        # Decorator pattern
    print(b.decorated_and_useful(string))    # Python decorator decorated the decorator pattern

【问题讨论】:

@Srikar 是正确的。 Here 是另一个你可能会觉得有趣的 SO 问题! @Srikar,我不能接受不能解决问题中描述的问题的回答,抱歉,我的问题中提出的大多数解决方案都不起作用。 FWIW,根据Python decorators 上的***文章:“尽管有名称,Python 装饰器并不是装饰器模式的实现”。它继续解释原因。 感谢@apcelent。这可能有助于任何人了解这个主题;) Srikar 的回答是绝对正确的。装饰器不适用于运行时修改。我的回答增加了一点细微差别,但他的回答他的回答是最好的。 codementor.io/@sheena/… 【参考方案1】:

装饰器模式 - 在面向对象编程中,装饰器模式是一种允许将行为动态添加到现有对象的设计模式。装饰器模式可用于在运行时扩展(装饰)某个对象的功能,独立于同一类的其他实例,前提是在设计时完成了一些基础工作。

Python 中的装饰器 - 尽管名称如此,Python 装饰器并不是装饰器模式的实现。装饰器模式是一种在静态类型的面向对象编程语言中使用的设计模式,允许在运行时向对象添加功能; Python 装饰器在定义时向函数和方法添加功能,因此是比装饰器模式类更高级别的构造。

装饰器模式本身在 Python 中很容易实现,因为该语言是鸭子类型的,因此通常不被视为鸭子类型。所以在 Python 中,装饰器是用于修改函数、方法或类定义的任何可调用 Python 对象。

我希望我把区别说清楚了。万一您不完全理解,请浏览这些链接。你会在它结束时变得更加清晰 -

How to make a chain of function decorators?

Implementing the decorator pattern in Python

What is the difference between using decorators and extending a sub class by inheritance?

Python Class Decorator

PyWiki - Python Decorators - A detailed discourse

Python Decorators Made Easy

Source 1 & source 2

【讨论】:

【参考方案2】:

区别是这样的:

(a) Python 装饰器与现有方法绑定并更改该方法的行为。示例:

@modifyBehavior
def original(myString):
    print myString

原始的行为被覆盖。您不能使用它来添加新功能。

(b) 装饰器模式是关于多态性的。在上面的示例代码中, Decorator.something_useful 的行为被覆盖。原来的方法丢失了。这不是真正的装饰器模式。您应该寻求增强或添加功能,而不是替换方法。您应该确保 a.something_useful(string) 返回与 b.something_useful(string) 相同的内容。事实上,在装饰器模式中,您通常会替换原始对象。这就是我的意思:

class Class(object):
    def __init__(self):
        pass
    def something_useful(self, string):
        return string

class Decorator(object):
    def __init__(self, wrapped):
        self._wrapped = wrapped
    def withUnderscores(self, string):
        return '_'.join(string.split(' '))
    def __getattr__(self, name):
        return getattr(self._wrapped, name)


if __name__ == '__main__':
    string = 'Lorem ipsum dolor sit amet.'
    obj = Class()
    print('Original: ', obj.something_useful(string))
    #This has no underscore function.  Use decorator to add.
    obj = Decorator(obj)
    print('Replaced spaces: ', obj.withUnderscores(string))
    print('Original still works: ', obj.something_useful(string))

您可以使用多个装饰器来添加功能。这使您可以仅在需要时添加所需的内容。更多阅读:GoF

【讨论】:

以上是关于Python 装饰器和装饰器模式有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

装饰器和指令在角度上有啥区别?

装饰器和指令在角度上有啥区别?

python 装饰器和 functools 模块

Python中上下文管理器和装饰器之间的区别

python函数下篇装饰器和闭包,外加作用域

PYTHON里的装饰器能装饰类吗