I'd like to have a class that adds in mixins based on arguments passed to the constructor. This is what I've tried:
class MixinOne(object):
def print_name(self):
print("{} is using MixinOne.".format(self.name))
class MixinTwo(object):
def print_name(self):
print("{} is using MixinTwo.".format(self.name))
class Sub(object):
def __new__(cls, *args, **kwargs):
mixin = args[1]
if mixin == 'one':
bases = (MixinOne,) + cls.__bases__
elif mixin == 'two':
bases = (MixinTwo,) + cls.__bases__
return object.__new__(type('Sub', bases, dict(cls.__dict__)))
def __init__(self, name, mixin):
print('In Sub.__init__')
self.name = name
The only problem with this seems to be that __init__
doesn't get called, so the print_name
methods will not work.
__init__
on Sub
to fire?or
This is a neat place to use metaclasses. You can put the custom-mixin-inclusion code in the meta, then your Sub
classes don't need to have the boilerplate:
class AutoMixinMeta(type):
def __call__(cls, *args, **kwargs):
try:
mixin = kwargs.pop('mixin')
name = "{}With{}".format(cls.__name__, mixin.__name__)
cls = type(name, (mixin, cls), dict(cls.__dict__))
except KeyError:
pass
return type.__call__(cls, *args, **kwargs)
class Sub(metaclass = AutoMixinMeta):
def __init__(self, name):
self.name = name
Now you can create Sub
objects and specify the mixin as follows:
>>> s = Sub('foo', mixin=MixinOne)
>>> s.print_name()
foo is using MixinOne.
It'll automatically get pulled out of the kwargs dict so the __init__
method can remain completely unaware of its existence.
Note: the metaclass declaration syntax in Python 2 is slightly different:
class Sub(object):
__metaclass__ = AutoMixinMeta
def __init__(self, name):
self.name = name
__init__
is only called if __new__
returns an instance of the class. Your on-the-fly class inherits from a mixin, and from Sub
's parents, but not from Sub
itself. It'll probably work if you set bases = (MixinOne, cls)
.
Write a factory function (or classmethod) instead of overloading Sub
's construction. Even better, just make some subclasses instead of creating classes at runtime. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With