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'>)
- [Django]-Site matching query does not exist
- [Django]-How do I input HTML into the help text of a Django form field?
- [Django]-Passing arguments to model methods in Django templates
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.
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
- [Django]-Django query case-insensitive list match
- [Django]-How to change field name in Django REST Framework
- [Django]-Which Model Field to use in Django to store longitude and latitude values?
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)
- [Django]-Exception Value:failed to find libmagic. Check your installation in windows 7
- [Django]-How to format time in django-rest-framework's serializer?
- [Django]-How do I get all the variables defined in a Django template?