如何确保为层次结构中的每个类调用方法(一次,如果存在)?

时间:2014-01-07 18:27:22

标签: python inheritance super method-resolution-order

我有一个类层次结构,其中子类可以选择性地定义具有给定名称的方法,比如do_it,并且想要在基类中编写一个函数,比如do_all,以确保每个这种方法将按类层次结构的顺序执行。我可以达到的最接近的目标是:

class A(object):
    def do_it(self):
        print 'Do A'

    def do_all(self):
        # Better, from comments and answers: vars(type(self))
        for c in reversed(self.__class__.__mro__[:-1]):
            c.do_it(self)

class B(A):
    def do_it(self):
        print 'Do B'

class C(B):
    def no_do_it(self):
        pass

class D(C):
    def do_it(self):
        print 'Do D'

这几乎按预期工作,例如B().do_all()给出

Do A
Do B

但是对于所有来自它的类,它会导致对B s do_it的重复调用。例如D().do_all()给出

Do A
Do B
Do B
Do D

如何避免从未实现父类do_it的类中重复调用?这甚至是实现我想要做的事情的正确方法吗?

1 个答案:

答案 0 :(得分:3)

您可以检查是否已经看到该功能:

def do_all(self):
    seen = set()
    for c in reversed(self.__class__.__mro__[:-1]):
        if c.do_it not in seen:
            seen.add(c.do_it)
            c.do_it(self)

请注意,在Python 2中,您需要从未绑定的方法中提取函数,如c.do_it.__func__(或使用six.get_unbound_function)。

另一种方法是检查__dict__

def do_all(self):
    for c in reversed(self.__class__.__mro__[:-1]):
        if 'do_it' in c.__dict__:
            c.do_it(self)