これは、メタクラスマジックを使用してそれを行う1つの方法です。IMHO、他のアプローチよりも堅牢で柔軟性があり、無制限の呼び出し(例Bar.write(x, "hello")
)と単一の継承を適切に処理します(以下のBazを参照)。
class ReverserMetaclass(type):
def __new__(cls, name, bases, dct):
""" This metaclass replaces methods of classes made from it
with a version that first calls their base classes
"""
# create a new namespace for the new class
new_dct = {}
for member_name, member in dct.items():
# only decorate methods/callable in the new class
if callable(member):
member = cls.wrap(bases, member_name, member)
new_dct[member_name] = member
# construct the class
return super(ReverserMetaclass, cls).__new__(cls, name, bases, new_dct)
# instead of the above, you can also use something much simpler
# dct['read'] = cls.wrap(bases, 'read', dct['read'])
# return super(ReverserMetaclass, cls).__new__(cls, name, bases, dct)
# if you have a specific method that you want to wrap and want to
# leave the rest alone
@classmethod
def wrap(cls, bases, name, method):
""" this method calls methods in the bases before calling the method """
def _method(*args, **kwargs):
for base in bases:
if hasattr(base, name):
getattr(base, name)(*args, **kwargs)
# put this above the loop if you want to reverse the call order
ret = method(*args, **kwargs)
return ret
return _method
コンソールの実行例:
>>> class Foo(object):
... __metaclass__ = ReverserMetaclass
... def write(self, s=""):
... # Make sure that overwritten
... # 'write' method in child class
... # does what it's specified, and
... # then what comes next...
... print "Write - From Foo", s
... def read(self):
... print "Read - From Foo"
...
>>> class Bar(Foo):
... def write(self, s=""):
... print "Write - from Bar", s
... def read(self):
... print "Read - From Bar"
...
>>> class Baz(Bar):
... def write(self, s=""):
... print "Write - from Baz", s
...
>>> x = Bar()
>>> x.write("hello")
Write - From Foo hello
Write - from Bar hello
>>> Bar.read(x)
Read - From Foo
Read - From Bar
>>>
>>> x = Baz()
>>> x.read()
Read - From Foo
Read - From Bar
>>> x.write("foo")
Write - From Foo foo
Write - from Bar foo
Write - from Baz foo
Pythonメタクラスは非常に強力ですが、他の人が言っているように、この種の魔法をあまり頻繁に実行したくない場合もあります。