在Python中实现装饰器模式

Bjö*_*lex 25 python design-patterns

我想在Python中实现装饰器模式,我想知道是否有一种方法可以编写一个装饰器来实现它想要修改的函数,而无需为所有刚转发到装饰对象的函数编写样板.像这样:

class foo(object):
    def f1(self):
        print "original f1"
    def f2(self):
        print "original f2"

class foo_decorator(object):
    def __init__(self, decoratee):
        self._decoratee = decoratee
    def f1(self):
        print "decorated f1"
        self._decoratee.f1()
    def f2(self):              # I would like to leave that part out
        self._decoratee.f2()
Run Code Online (Sandbox Code Playgroud)

foo_decorator.f2想要decoratee.f2自动转发电话.有没有办法编写一个泛型方法,将所有未实现的函数调用转发给decoratee

Phi*_*ipp 32

你可以使用__getattr__:

class foo(object):
    def f1(self):
        print "original f1"
    def f2(self):
        print "original f2"

class foo_decorator(object):
    def __init__(self, decoratee):
        self._decoratee = decoratee
    def f1(self):
        print "decorated f1"
        self._decoratee.f1()
    def __getattr__(self, name):
        return getattr(self._decoratee, name)

u = foo()
v = foo_decorator(u)
v.f1()
v.f2()
Run Code Online (Sandbox Code Playgroud)

  • 这是一个好主意。但是,应该注意的是,如果您使用抽象基类(即导入 abc 并使用 __metaclass__ = abc.ABCMeta 来定义抽象方法和属性),那么它将不起作用。 (2认同)

Ale*_*mas 9

作为菲利普回答的附录; 如果您不仅要装饰,而且保留对象的类型,Python允许您在运行时子类化实例:

class foo(object):
    def f1(self):
        print "original f1"

    def f2(self):
        print "original f2"


class foo_decorator(object):
    def __new__(cls, decoratee):
        cls = type('decorated',
                   (foo_decorator, decoratee.__class__),
                   decoratee.__dict__)
        return object.__new__(cls)

    def f1(self):
        print "decorated f1"
        super(foo_decorator, self).f1()


u = foo()
v = foo_decorator(u)
v.f1()
v.f2()
print 'isinstance(v, foo) ==', isinstance(v, foo)
Run Code Online (Sandbox Code Playgroud)

这比您的示例所涉及的要多得多,您可以提前知道正在装饰的类.

可能就足够了:

class foo_decorator(foo):
    def __init__(self, decoratee):
        self.__dict__.update(decoratee.__dict__)

    def f1(self):
        print "decorated f1"
        super(foo_decorator, self).f1()
Run Code Online (Sandbox Code Playgroud)