[Django]-How to call super of enclosing class in a mixin in Python?

29👍

✅

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

14👍

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'>)

8👍

@Click2Death answer is correct, however, when you call super().test() inside your mixin class most IDE will claim that test is unresolved, which is correct.

enter image description here

Here is how to make your IDE happy and your code better.

class Parent(object):
    def test(self):
        print("parent")


class MyMixin(object):
    def test(self):
        super_test = getattr(super(), 'test')
        if super_test and callable(super_test):
            super_test()
        print("mixin")


class MyClass(MyMixin, Parent):
    def test(self):
        super().test()
        print("self")

if __name__ == "__main__":
    my_obj = MyClass()
    my_obj.test()

This is Python 3 code, to make it working with Python 2 you need to pass two arguments to the super(MyClass, self) call

4👍

Django Example (Python 3+)

To expand on Vladimir Prudnikov’s answer in a Django context, the template view mixin class could be structured as shown below.

from django.views.generic.base import View


class MyViewMixin:

    def dispatch(self, request, *args, **kwargs):
        super_dispatch = getattr(super(), 'dispatch')
        if super_dispatch and callable(super_dispatch):
            return super_dispatch(request, *args, **kwargs)
        raise RuntimeError('MyViewMixin must be used as part of a '
            'multiple inheritance chain that includes a Django template-view')


class MyCustomView(MyViewMixin, View):

    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

Leave a comment