Recipe for MixIns in PythonLanguage which allows in-place runtime mixing and unmixing. As a bonus, there is a 'functional-style' mixin function, which preserves the base class.
def mixIn (base, addition):
"""Mixes in place, i.e. the base class is modified.
Tags the class with a list of names of mixed members.
"""
assert not hasattr(base, '_mixed_')
mixed = []
for item, val in addition.__dict__.items():
if not hasattr(base, item):
setattr(base, item, val)
mixed.append (item)
base._mixed_ = mixed
def unMix (cla):
"""Undoes the effect of a mixin on a class. Removes all attributes that
were mixed in -- so even if they have been redefined, they will be
removed.
"""
for m in cla._mixed_: #_mixed_ must exist, or there was no mixin
delattr(cla, m)
del cla._mixed_
def mixedIn (base, addition):
"""Same as mixIn, but returns a new class instead of modifying
the base.
"""
class newClass: pass
newClass.__dict__ = base.__dict__.copy()
mixIn (newClass, addition)
return newClass
Old recipe
def mixin (existingClass, mixinClass):
for item, val in mixinClass.__dict__.items():
if not hasattr(existingclass, item):
setattr(existingclass, item, val)
This copies not just functions, but any class members.
Example usage:
class addSubMixin:
def add(self, value):
return self.number + value
def subtract(self, value):
return self.number - value
class myClass:
def __init__(self, number):
self.number = number
Then, at runtime, you can mix any class into any other with:
mixin(myClass, addSubMixin)
myInstance = myClass(4)
myInstance.add(2)
myInstance.subtract(2)
why not do it like this:
class myClass(myClass, myMixin)
pass
because it is not at runtime.
Person.__bases__ assignment can be made at runtime, for e.g. driver selection.
CAUTION the assignment is to the class.
Good examples of MixIns in the PythonLanguage are in SocketServer module from standard library.
such as:
class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
You just choose the flavors and add them in. Wants forking? add ForkingMixIn.
see also Twisted Python and wxPython for a lot of MixIn uses.
--JuneKim
This does not work for new-style classes, right?
See MixIn.