0

I have code like this:

class X(object):
    def __init__(self):
        print('X')
    def Print(self):
        print('X')


class Y(object):
    def __init__(self):
        print('Y')
    def Print(self):
        print('Y')

class Z(X,Y):
    def __init__(self):
        print('Z')
        def Print(self):
            print('z')
            super().Print()

>>> z=Z()
Z
>>> z.Print()
X

It searches for Print according to

Z.__mro__
(<class '__main__.Z'>, <class '__main__.X'>, <class '__main__.Y'>, <class 'object'>)

and find it for first time in X. But if I want to z.Print() run Y.Print(), I can use an explicit class name like:

class Z(X,Y):
    def __init__(self):
        print('Z')
        def Print(self):
            print('z')
            Y.Print()

but this is not dynamic. Is there a better way to do this?

6
  • Well, you could define Z as class Z(Y, X) if you want the classes to be inherited in the other order. Is that what you're asking? Commented Sep 27, 2015 at 6:54
  • no ,I want to do this with out changing the inheritance orders Commented Sep 27, 2015 at 6:55
  • 5
    And how do you expect Python to guess which one you want to use if you insist on defining them out of order? You could always do self.__class__.__bases__[1].Print() if you always want to pick the 2nd parent class, but if you do, remind me never to work with you.. Commented Sep 27, 2015 at 6:59
  • 1
    @ZeroDays: In what sense do you want it to be "dynamic"? You can either use the inheritance order, or you can explicitly say which class you want to use, but there aren't really any other options that make sense. How do you expect Python to know which one you want to use? Commented Sep 27, 2015 at 7:01
  • 3
    If you want to preserve the inheritance order (that is, have all of X's methods take priority over Y's), except for that one call, then yes, I would say using Y explicitly for that call is your best option. Commented Sep 27, 2015 at 7:04

2 Answers 2

2

I really depends what you are trying to do. If you want to make sure both X.Print and Y.Print are called then you need to add super calls in both X.Print and Y.Print, and an a base class with a place holder Print method.

If you want to call X.Print or Y.Print depending on some criteria, then inheritance may be the wrong model for you. You may wish to try using composition. This is where you write a class that does not inherit from X or Y, but has instances of them as members and knows how to use them. eg.

Inheritance

from abc import abstractmethod, ABCMeta

class Base(metaclass=ABCMeta):
    @abstractmethod
    def Print(self):
        pass

class X(Base):
    def Print(self):
        print("X")
        super().Print()

class Y(Base):
    def Print(self):
        print("Y")
        super().Print()

class Inheritance(X, Y):
    def Print(self):
        print("Inheiritance")
        super().Print()

Inheritance().Print()

Outputs:

Inheiritance
X
Y

Composition

class Composition:
    def __init__(self):
        self.x = X()
        self.y = Y()
    def Print(self):
        print("Composition")
        self.x.Print()
        self.y.Print()

Composition().Print()

Outputs:

Composition
X
Y
Sign up to request clarification or add additional context in comments.

1 Comment

Without knowing what X, Y and Z are it's though to really know what model applies, but I concur on the composition advice. Composition over Inheritance (en.wikipedia.org/wiki/Composition_over_inheritance).
1

For future reference purposes, here is a summary of the options that were discussed in the comments.

1. Change the order of inheritance

class Z(Y, X):
    ...

That would ensure that Y's methods are called over X's methods when using super, including the Print method.

2. Explicitly call Y's Print method

class Z(X, Y):
    ...
    def Print(self):
        Y.Print(self)

That would ensure that X's methods are called over Y's methods when using super, except for that one call, which would explicitly call Y's Print.

3. (Do not use) Explicitly call the second parent class's method

class Z(X, Y):
    ...
    def Print(self):
        self.__class__.__bases__[1].Print()

That would ensure that X's methods are called over Y's methods when using super, except for that one call, which would explicitly call the second parent class's Print (in this case, Y).

2 Comments

in option 2, that should be Y.Print(self)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.