Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Mixin class __init__ functions not automatically called?

I'd like to use a Mixin to always add some init functionality to my child classes which each inherit from different API base classes. Specifically, I'd like to make multiple different child classes that inherit from one of these different API-supplied base classes and the one Mixin, which will always have the Mixin initialization code executed in the same way, without code replication. However, it seems that the __init__ function of the Mixin class never gets called unless I explicitly call it in the Child class's __init__ function, which is less than ideal. I've built up a simple test case:

class APIBaseClassOne(object):     def __init__(self, *args, **kwargs):         print (" base ")  class SomeMixin(object):     def __init__(self, *args, **kwargs):         print (" mixin before ")         super(SomeMixin, self).__init__(*args, **kwargs)         print (" mixin after ")  class MyClass(APIBaseClassOne):     pass  class MixedClass(MyClass, SomeMixin):     pass 

As you can see in the following output, the Mixin function's init never gets called:

>>> import test >>> test.MixedClass()  base <test.MixedClass object at 0x1004cc850> 

Is there a way to do this (have an init function in a Mixin get called) without writing every child class to explicitly invoke the Mixin's init function? (i.e., without having to do something like this in every class:)

class MixedClass(MyClass, SomeMixin):     def __init__(*args, **kwargs):         SomeMixin.__init__(self, *args, **kwargs)         MyClass.__init__(self, *args, **kwargs)  

Btw, if all my child classes were inheriting from same base class, I realize I could create a new middle class that inherits from the base class and the mixin and keep it DRY that way. However, they inherit from different base classes with common functionality. (Django Field classes, to be precise).

like image 701
B Robster Avatar asked May 23 '11 14:05

B Robster


People also ask

How does a mixin work?

Mixins are a language concept that allows a programmer to inject some code into a class. Mixin programming is a style of software development, in which units of functionality are created in a class and then mixed in with other classes. A mixin class acts as the parent class, containing the desired functionality.

What is a mixin class in Sklearn?

A mixin is a class that provides method implementations for reuse by multiple related child classes. However, the inheritance is not implying an is-a relationship. A mixin doesn't define a new type. Therefore, it is not intended for direction instantiation.

What is the difference between a mixin and inheritance?

Mixins are sometimes described as being "included" rather than "inherited". In short, the key difference from an inheritance is that mix-ins does NOT need to have a "is-a" relationship like in inheritance. From the implementation point of view, you can think it as an interface with implementations.

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.


2 Answers

Sorry I saw this so late, but

class MixedClass2(SomeMixin, MyClass):     pass  >>> m = MixedClass2()  mixin before   base   mixin after 

The pattern @Ignacio is talking about is called cooperative multiple inheritance, and it's great. But if a base class isn't interested in cooperating, make it the second base, and your mixin the first. The mixin's __init__() (and anything else it defines) will be checked before the base class, following Python's MRO.

This should solve the general question, though I'm not sure it handles your specific use. Base classes with custom metaclasses (like Django models) or with strange decorators (like @martineau's answer ;) can do crazy things.

like image 84
Matt Luongo Avatar answered Oct 15 '22 16:10

Matt Luongo


Have the base class invoke super().__init__() even though it is a subclass of object. That way all the __init__() methods will be run.

class BaseClassOne(object):     def __init__(self, *args, **kwargs):         super(BaseClassOne, self).__init__(*args, **kwargs)         print (" base ") 
like image 30
Ignacio Vazquez-Abrams Avatar answered Oct 15 '22 15:10

Ignacio Vazquez-Abrams