python装饰器是否严格实现了装饰器模式?

时间:2011-12-14 13:05:44

标签: python design-patterns decorator

我参加了一个关于装饰器模式的会话,其中提供的大多数示例都在java中。例如,在下面的示例中,Pizza对象正在使用两个浇头进行装饰。

Pizza vegPizza = new ToppingsType1(new ToppingType2(new Pizza()))

在python中,我看到装饰器正在这样的场景中使用

@applyTopping2
@applyTopping1
makePizza():
    pass

虽然在这里我可以看到makePizza函数正在使用两个函数进行修饰,但它与java的基于类的方法有很大不同。 我的问题是python decorators是否严格实现了decorator模式,或者实现有点不同但想法是一样的。

PS:我不知道在哪里查找装饰器模式的标准定义。虽然维基百科给出了一个动态语言(JS)的例子,但我的问题仍然很好:)

3 个答案:

答案 0 :(得分:2)

你应该read this解释什么是python的装饰器。

  

我们与Python有关的“装饰者”与DecoratorPattern [...]并不完全相同。 Python装饰器是对Python语法的一种特定更改,它允许我们更方便地更改函数和方法(以及未来版本中可能的类)。这支持DecoratorPattern更易读的应用程序,但也支持其他用途。

因此,您将能够使用python的装饰器实现“经典”装饰器模式,但是您可以使用这些装饰器做更多(有趣;))事情。

在您的情况下,它可能看起来像:

def applyTopping1(functor):
    def wrapped():
        base_pizza = functor()
        base_pizza.add("mozzarella")
        return base_pizza
    return wrapped

def applyTopping2(functor):
    def wrapped():
        base_pizza = functor()
        base_pizza.add("ham")
        return base_pizza
    return wrapped

然后你会得到一个玛格丽特:)

答案 1 :(得分:1)

不是一个真正的答案,只是一个关于如何用Python做事的有趣例子 - 与静态语言相比:

def pizza_topping_decorator_factory(topping):
    def fresh_topping_decorator(pizza_function):
        def pizza_with_extra_topping(*args, **kw):
            return pizza_function(*args, **kw) + ", " + topping
        return pizza_with_extra_topping
    return fresh_topping_decorator


mozzarela = pizza_topping_decorator_factory("mozarella")
anchove = pizza_topping_decorator_factory("anchove")

@anchove
@mozzarela
def pizza():
    return "Pizza"

在Python控制台上粘贴此代码时:

>>> 
>>> print pizza()
Pizza, mozarella, anchove

答案 2 :(得分:1)

Python中的@decorator语法只不过是语法糖。

代码

@decorator
def foo():
    pass

只不过是

def foo():
    pass

foo = decorator(foo)

最终结果取决于你想要的是什么。

您可以将类用作decorator,并使用foo作为__init__ arg从此类实例化对象。

您可以使用一些参数实例化的对象作为装饰器,如下面的代码

class Decorator(object):
    def __init__(self, arg1, arg2):
        pass

    def __call__(self, foo):
        return foo()

@Decorator(arg1_value, arg2_value)
def foo():
    pass

只有你决定你的代码会是什么样子,以及它不会出现任何模式或者来自java世界的人:)