I have created a Python class called Liger
, which extends a class called Lion
and a class called Tiger
. The class Liger
inherits the method speak()
from both Lion
and Tiger
, but the syntax is valid nonetheless - no error message is printed, but instead, Tiger
's implementation of the speak()
method is inherited by Liger
. Is it possible to detect method name collisions like this one in Python, so that an error message is printed when method names conflict in this way?
'''
Conflicting method names in python
'''
class Tiger():
@staticmethod
def speak():
print "Rawr!";
class Lion():
@staticmethod
def speak():
print "Roar!";
class Liger(Tiger, Lion):
pass
'''both superclasses define a speak() method, and I need a way to detect this type of conflict.'''
Liger.speak(); ''' this prints "Rawr" instead of printing an error message. '''
'''Is there any way to detect method name collisions like this one?'''
The code can be tested and debugged online here: http://ideone.com/xXOoVq
The Method Resolution Order (MRO) is the set of rules that construct the linearization. In the Python literature, the idiom "the MRO of C" is also used as a synonymous for the linearization of the class C.
The Diamond ProblemIt refers to an ambiguity that arises when two classes Class2 and Class3 inherit from a superclass Class1 and class Class4 inherits from both Class2 and Class3.
A class can be derived from more than one base class in Python, similar to C++. This is called multiple inheritance. In multiple inheritance, the features of all the base classes are inherited into the derived class. The syntax for multiple inheritance is similar to single inheritance.
I'm not sure if inheritance is the right mechanism for you to use to solve your problem. Inheritance is often said to define an an "IS-A" relationship between two classes. That is, if A
inherits from B
, every instance of B
is an instance of A
also.
If you're using multiple inheritance, the class ends up being multiple kinds of object at once. In your example, a Liger
instance, is both a Tiger
and a Lion
at the same time.
You probably don't want to be using class inheritance to model species inheritance. Despite the name, they don't really mean the same thing. For instance, housecats are probably descended from something quite tigerish, but it would not be correct to say that a housecat IS-A tiger.
The fact that you're using static methods on your classes makes me think that perhaps you don't want to be using classes at all, but rather instances of a more generic Animal
class:
class Animal(object):
def __init__(self, sound):
self.sound = sound
def speak(self):
print self.sound
lion = Animal("Roar!")
There's no mechanism for inheritance there, but it would be possible to add a method that mutates one kind of Animal into another one in some way.
Now, if you are really set on using classes and multiple inheritance, there are two decent approaches (using regular instance methods, rather than static methods):
The first is to do "collaborative multiple inheritance", and have each of your methods call the same method on the next class in the MRO. Usually you need to inherit from a common base class to make this work (otherwise the last call to super
will get object
, which won't have the method defined):
class Animal(object):
def speak(self):
pass
class Lion(Animal):
def speak(self):
print("Roar!")
super(Lion, self).speak()
class Tiger(Animal):
def speak(self):
print("Rawr!")
super(Tiger, self).speak()
class Liger(Lion, Tiger):
pass
In this situation, a Liger
instance's speak
method will print both Roar
then Rawr
, which makes sense since it's both a lion and a tiger at once. Be careful with this style of coding though, as it can be tricky to get the collaboration to work right. For instance, you can't change a method signature and expect it to work correctly in a collaborative multiple inheritance situation (unless you use only keyword arguments, and pass along any unrecognized ones in **kwargs
).
The second solution is to give Liger
it's own speak
implementation that explicitly chooses what to do (which may be to call one of its base classes). This is required in some other languages, like C++. If the inheritance you've requested isn't doing what you want, it's probably the most straightforward way to fix it:
class Liger(Lion, Tiger):
def speak(self):
Tiger.speak(self)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With