在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
呢?
7 个回答
2
虽然这可能不是最好的做法,但你可以给实例添加功能,就像我为了将我的代码从Django的ORM迁移到SQLAlchemy时所做的那样,具体方法如下:
def _save(self):
session.add(self)
session.commit()
setattr(Base,'save',_save)
10
作为对Philipp回答的补充;如果你不仅想给一个对象加装饰,还想保持它的类型,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()
33
你可以使用 __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()