在Python中实现装饰器模式[英] Implementing the decorator pattern in Python

本文是小编为大家收集整理的关于在Python中实现装饰器模式的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我想实现 decorator模式在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()

我想自动打电话给foo_decorator.f2 foo_decorator.f2.有没有办法编写通用方法,将所有未完成的函数呼叫转发到decoratee?

推荐答案

您可以使用__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()

其他推荐答案

作为菲利普答案的附录;如果您不仅需要装饰,还需要保留对象的 type ,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)

这比您的示例严格涉及的要多一些,您知道该课程已提前装饰.

这个可能就足够了:

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

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

其他推荐答案

可以说不是最好的做法,但是您可以在实例中添加功能,因为我为帮助我的代码从Django的ORM过渡到Sqlalachemy,如下所示:

def _save(self):
    session.add(self)
    session.commit()
setattr(Base,'save',_save)

本文地址:https://www.itbaoku.cn/post/627620.html

问题描述

I want to implement the decorator pattern in Python, and I wondered if there is a way to write a decorator that just implements the function it wants to modify, without writing boiler-plate for all the functions that are just forwarded to the decorated object. Like so:

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

I would like to have calls to foo_decorator.f2 forwarded to decoratee.f2 automatically. Is there a way to write a generic method that forwards all unimplemented function-calls to decoratee?

推荐答案

You could use __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()

其他推荐答案

As an addendum to Philipp's answer; if you need to not only decorate, but preserve the type of an object, Python allows you to subclass an instance at runtime:

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)

This is a bit more involved than strictly necessary for your example, where you know the class being decorated in advance.

This might suffice:

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

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

其他推荐答案

It's arguably not the best practice, but you can add functionality to instances, as I've done to help transition my code from Django's ORM to SQLAlachemy, as follows:

def _save(self):
    session.add(self)
    session.commit()
setattr(Base,'save',_save)