Реализация шаблона "декоратор" в Python

Я хочу реализовать шаблон "декоратор" в 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 переданный decoratee.f2 автоматически. Есть ли способ записать общий метод что вперед все нереализованные вызовы функции к decoratee?

25
задан Björn Pollex 25 June 2010 в 14:45
поделиться

4 ответа

Можно использовать __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()
32
ответ дан 28 November 2019 в 21:03
поделиться

Возможно, это не лучшая практика, но вы можете добавить функциональность к экземплярам, ​​как я сделал, чтобы помочь перевести мой код из ORM Django в SQLAlachemy, как показано ниже:

def _save(self):
    session.add(self)
    session.commit()
setattr(Base,'save',_save)
2
ответ дан 28 November 2019 в 21:03
поделиться

В качестве дополнения к ответу Филиппа; если вам нужно не только украсить, но и сохранить тип объекта, 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()
9
ответ дан 28 November 2019 в 21:03
поделиться

Схема UML в связанной статье в Википедии неверна, как и ваш код.

Если вы следуете «шаблону декоратора», класс декоратора является производным от базового декорированного класса. (На схеме UML стрелка наследования от WindowDecorator до Window отсутствует).

с

class foo_decorator(foo):

вам не нужно реализовывать недекорированные методы.

Кстати: в языках со строгой типизацией есть еще одна причина, по которой декоратор должен быть производным от декорированного класса: иначе вы не сможете связывать декораторы.

2
ответ дан 28 November 2019 в 21:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: