import types
def MixIn(pyClass, mixInClass, makeAncestor=0):
if makeAncestor:
if mixInClass not in pyClass.__bases__:
pyClass.__bases__ = (mixInClass,) + pyClass.__bases__
else:
# Recursively traverse the mix-in ancestor
# classes in order to support inheritance
baseClasses = list(mixInClass.__bases__)
baseClasses.reverse()
for baseClass in baseClasses:
MixIn(pyClass, baseClass)
# Install the mix-in methods into the class
for name in dir(mixInClass):
if not name.startswith('__'):
# skip private members
member = getattr(mixInClass, name)
if type(member) is types.MethodType:
member = member.im_func
setattr(pyClass, name, member)
这个函数可以将某个mix-in类安装为指定类的基类,同时可以通过关键字参数指定在基类中的顺序,是最前还是最后。因为Python在处理基类时,是安顺序进行的,所以安装在最前则优先级最高。同时对于指定类的方法如果在mix-in类中存在,则将指定类中的方法替换成mix-in类中的方法。
if makeAncestor:
if mixInClass not in pyClass.__bases__:
pyClass.__bases__ = (mixInClass,) + pyClass.__bases__
如果makeAncestor为1,表示是安装在最前,则首先判断在pyClass的基类中是否存在mixInClass类,如果不存在,再进行安装。
else:
# Recursively traverse the mix-in ancestor
# classes in order to support inheritance
baseClasses = list(mixInClass.__bases__)
baseClasses.reverse()
for baseClass in baseClasses:
MixIn(pyClass, baseClass)
如果makeAncestor为0,并不将mixInClass安装在最后,原作者说他在实际中没有这样用的。那么它完成什么任务呢?它实际完成了一个递归,即从mixInClass的最底层的基类开始(因为mixInClass也可能是多重继承而来的),对pyClass中也存在的函数进行替换。这样执行完毕后,mixInClass类中,包含所有基类中的函数,如果有与pyClass类中的函数重名的,都将pyClass中的函数替换成mixInClass相应的函数。(有些复杂!)
# Install the mix-in methods into the class
for name in dir(mixInClass):
if not name.startswith('__'):
# skip private members
member = getattr(mixInClass, name)
if type(member) is types.MethodType:
member = member.im_func
setattr(pyClass, name, member)
这步完成重名函数的替换。首先去掉私有方法(私有方法名前有'__').得到mixInClass类中的指定名字的方法对象,判断是否为方法类型。因为还有可能取到属性。在types模块中包含了一些类型,可以用它来判断是否为方法类型。对于方法对象,如果是类方法,实际的函数应使用它的属性im_func。然后将pyClass相应的方法替换成mixInClass中的方法。
这样就将mixInClass安装为pyClass的基类了。
使用例子如:
from classa import classa
from classb import classb
MixIn(classa, classb) #将classb安装为classa的基类