Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to detect conflicting method names in Python?

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

like image 234
Anderson Green Avatar asked Mar 10 '13 22:03

Anderson Green


People also ask

What is __ MRO __ Python?

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.

Do we have diamond problem in Python?

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.

Is multiple inheritance Pythonic?

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.


1 Answers

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)
like image 137
Blckknght Avatar answered Oct 20 '22 14:10

Blckknght