Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call super of enclosing class in a mixin in Python?

Tags:

I have the following code, in Django:

class Parent(models.Model):     def save(self):         # Do Stuff A  class Mixin(object):     def save(self):         # Do Stuff B  class A(Parent, Mixin):     def save(self):         super(A, self).save()         # Do stuff C 

Now, I want to use the mixin without blatting the behaviour of the save in Parent. So I when I save, I want to do stuff C, B, and A. I've read Calling the setter of a super class in a mixin however I don't get it and having read the super docs it doesn't seem to answer my question.

THe question is, what do I put in the mixin to make sure it does stuff B and doesn't stop Stuff A from happening?

like image 302
David Boshton Avatar asked Sep 08 '16 16:09

David Boshton


People also ask

How do you call super super class in Python?

Using Super(): Python super() function provides us the facility to refer to the parent class explicitly. It is basically useful where we have to call superclass functions. It returns the proxy object that allows us to refer parent class by 'super'.

Can a mixin override a method?

The answer is, the mixin method completely overwrites the original method.

How does Python mixin work?

Mixins are an alternative class design pattern that avoids both single-inheritance class fragmentation and multiple-inheritance diamond dependencies. A mixin is a class that defines and implements a single, well-defined feature. Subclasses that inherit from the mixin inherit this feature—and nothing else.

Can a mixin inherit from another mixin?

It's perfectly valid for a mixin to inherit from another mixin - in fact, this is how most of Django's more advanced mixins are made. However, the idea of mixins is that they are reusable parts that, together with other classes, build a complete, usable class.


2 Answers

How about calling super in your mixin class?

class Parent(object):     def test(self):         print("parent")   class MyMixin(object):     def test(self):         super(MyMixin, self).test()         print("mixin")   class MyClass(MyMixin, Parent):     def test(self):         super(MyClass, self).test()         print("self")  if __name__ == "__main__":     my_obj = MyClass()     my_obj.test() 

This will give you the output as:

$ python test.py parent mixin self 
like image 188
Click2Death Avatar answered Oct 02 '22 15:10

Click2Death


The best practice for calling the implementation from the superclass is to use super():

class Mixin(object):     def save(self):         super(Mixin, self).save()         # Do Stuff B here or before super call, as you wish 

What is important is that you call super() in each class (so that it propagates all the way) but not the topmost (base) class, because its superclass does not have save().

Note that when you call super(Mixin, self).save(), you don't really know what the super class would be once it is executed. That will be defined later.

Unlike some other languages, in python, the end class will always have a linear list of classes from which it inherits. That is called MRO (Method Resolution Order). From MRO Python decides what to do on super() call. You can see what the MRO is for your class this way:

>>> A.__mro__ (<class '__main__.A'>, <class '__main__.Parent'>, <class '__main__.Model'>, <class '__main__.Mixin'>, <type 'object'>) 

So, A's super is Parent, Parent's super is Model, Model's super is Mixin and Mixin's super is object.

That is wrong, so you should change A's parents to:

class A(Mixin, Parent): 

Then you'd have a better MRO:

>>> A.__mro__ (<class '__main__.A'>, <class '__main__.Mixin'>, <class '__main__.Parent'>, <class '__main__.Model'>, <type 'object'>) 
like image 44
zvone Avatar answered Oct 02 '22 17:10

zvone