1

In Python if you have a class that extends 2 or more classes, how does it know which class method to call if they all have a method titled save?

class File(models.Model, Storage, SomethingElse):

    def run(self):
        self.save()

What if Storage has a save(), and what is SomethingElse() has a save()? Can anyone briefly explain?

3
  • Someone made a post that had a really good answer then deleted it! Commented Jul 19, 2013 at 13:41
  • 1
    In practice, you'll want to write your own save which replaces or calls the base class methods. Commented Jul 19, 2013 at 13:43
  • I am new to Multiple Extending and I am not sure if this is the best way to go about it.. However, this is a nagging question on my mind! Commented Jul 19, 2013 at 13:45

2 Answers 2

3

Python supports a limited form of multiple inheritance as well. A class definition with multiple base classes looks as follows:

class DerivedClassName(Base1, Base2, Base3): . . .

The only rule necessary to explain the semantics is the resolution rule used for class attribute references. This is depth-first, left-to-right. Thus, if an attribute is not found in DerivedClassName, it is searched in Base1, then (recursively) in the base classes of Base1, and only if it is not found there, it is searched in Base2, and so on.

So in your example if all 3 classes have method save instances of File will use method save from models.Model

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

6 Comments

That makes sense, very interesting.. What if Base1 had a save() and you wanted to access Base2's save()? Is that possible?
@JREAM Yes, this is why you pass a baseclass to super.
depth-first, left-to-right really only applies to old-style classes. new-style classes that's approximately right, but not exactly. You can look at the __mro__ attribute to see the actual method resolution order.
@Marcin -- That's not exactly a time for super. super will call Base1.save also (assuming that everything else uses super properly). Ultimately, if you only want to call Base2.save, you need to do so explicitly: Base2.save(self,args)
@mgilson super(Base2,self).save() will do it.
|
1

In practice, when this occurs, you'll likely want to write your own save which either replaces or uses one of the base class methods.

Let's say you want to just call them:

class MyFile(models.Model, Storage, SomethingElse): #file is a builtin class. Confusion will abound

    def run(self):
        self.save()

    def save():
        super(Storage, self).save() # start search for method in Storage
        super(models.Model,self).save() # start search for method in models.Model

NOTE HOWEVER that if the mro (see: http://www.python.org/download/releases/2.3/mro/) of models.Model doesn't contain a save, and Storage does, you'll end up calling the same method twice.

A fuller exploration is here: http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ (and now linked to from the official docs).

Comments

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.