Я хочу реализовать шаблон "декоратор" в 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
?
Можно использовать __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()
Возможно, это не лучшая практика, но вы можете добавить функциональность к экземплярам, как я сделал, чтобы помочь перевести мой код из ORM Django в SQLAlachemy, как показано ниже:
def _save(self):
session.add(self)
session.commit()
setattr(Base,'save',_save)
В качестве дополнения к ответу Филиппа; если вам нужно не только украсить, но и сохранить тип объекта, 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()
Схема UML в связанной статье в Википедии неверна, как и ваш код.
Если вы следуете «шаблону декоратора», класс декоратора является производным от базового декорированного класса. (На схеме UML стрелка наследования от WindowDecorator до Window отсутствует).
с
class foo_decorator(foo):
вам не нужно реализовывать недекорированные методы.
Кстати: в языках со строгой типизацией есть еще одна причина, по которой декоратор должен быть производным от декорированного класса: иначе вы не сможете связывать декораторы.