Question

I have a class hierarchy in which subclasses may optionally define a method with a given name, say do_it, and want to write a function, say do_all, in the base class that ensures that each such method will be executed, in order of class hierarchy. The closest I can get to achieving this is something like:

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'

This almost works as intended, for example B().do_all() gives

Do A
Do B

But it results in a duplicate call to Bs do_it for all classes descended from it. For example D().do_all() gives

Do A
Do B
Do B
Do D

How can I avoid the duplicate call to a parent's do_it from classes that do not implement it? Is this even the right way to achieve what I'm trying to do?

Était-ce utile?

La solution

You can check whether the function has already been seen:

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)

Note that in Python 2 you'll need to extract the function from the unbound method, as c.do_it.__func__ (or use six.get_unbound_function).

An alternative is to examine __dict__:

def do_all(self):
    for c in reversed(self.__class__.__mro__[:-1]):
        if 'do_it' in c.__dict__:
            c.do_it(self)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top