在Python编程中,Mark Lutz提到了术语mixin。我有C/ c++ / c#的背景,以前没有听说过这个术语。什么是mixin?
从这个例子的字里行间(我链接了这个例子,因为它很长),我假设这是一个使用多重继承来扩展类的情况,而不是适当的子类化。这样对吗?
为什么我要这样做,而不是把新功能放到一个子类?就此而言,为什么混合/多重继承方法会比使用组合更好呢?
mixin与多重继承的区别是什么?这只是语义上的问题吗?
在Python编程中,Mark Lutz提到了术语mixin。我有C/ c++ / c#的背景,以前没有听说过这个术语。什么是mixin?
从这个例子的字里行间(我链接了这个例子,因为它很长),我假设这是一个使用多重继承来扩展类的情况,而不是适当的子类化。这样对吗?
为什么我要这样做,而不是把新功能放到一个子类?就此而言,为什么混合/多重继承方法会比使用组合更好呢?
mixin与多重继承的区别是什么?这只是语义上的问题吗?
当前回答
我建议不要在新的Python代码中使用mix-in,如果你能找到其他方法(比如用复合代替继承,或者只是把方法打补丁到你自己的类中),这样做并不费力。
在老式的类中,您可以使用mix- In作为从另一个类中抓取一些方法的一种方式。但在新风格的世界里,一切,甚至是混合,都继承自对象。这意味着任何多重继承的使用都会自然地引入MRO问题。
在Python中有很多方法可以使多继承MRO工作,最著名的是super()函数,但这意味着您必须使用super()来完成整个类层次结构,并且要理解控制流要困难得多。
其他回答
这个答案旨在通过以下例子解释mixin:
自包含:简短,不需要知道任何库来理解示例。 Python,而不是其他语言。 可以理解,这里有来自其他语言(如Ruby)的例子,因为这个术语在这些语言中更常见,但这是一个Python线程。
它还应审议有争议的问题:
对于mixin的特征来说,多重继承是必要的还是不必要的?
定义
我还没有看到一个“权威”来源的引用清楚地说明什么是Python中的mixin。
我已经看到了mixin的两种可能的定义(如果它们被认为不同于其他类似的概念,如抽象基类),人们并不完全同意哪一种是正确的。
不同语言之间的共识可能有所不同。
定义1:无多重继承
mixin是这样一个类,该类的一些方法使用了类中没有定义的方法。
因此,该类并不意味着要被实例化,而是作为基类使用。否则,实例将具有在不引发异常的情况下无法调用的方法。
一些源代码添加的约束是类不能包含数据,只能包含方法,但我不明白为什么这是必要的。然而在实践中,许多有用的mixin没有任何数据,没有数据的基类使用起来更简单。
一个经典的例子是从<=和==中实现所有比较运算符:
class ComparableMixin(object):
"""This class has methods which use `<=` and `==`,
but this class does NOT implement those methods."""
def __ne__(self, other):
return not (self == other)
def __lt__(self, other):
return self <= other and (self != other)
def __gt__(self, other):
return not self <= other
def __ge__(self, other):
return self == other or self > other
class Integer(ComparableMixin):
def __init__(self, i):
self.i = i
def __le__(self, other):
return self.i <= other.i
def __eq__(self, other):
return self.i == other.i
assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)
# It is possible to instantiate a mixin:
o = ComparableMixin()
# but one of its methods raise an exception:
#o != o
这个特殊的例子可以通过functools. total_ordered()装饰器来实现,但这里的游戏是重新发明轮子:
import functools
@functools.total_ordering
class Integer(object):
def __init__(self, i):
self.i = i
def __le__(self, other):
return self.i <= other.i
def __eq__(self, other):
return self.i == other.i
assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)
定义2:多重继承
mixin是一种设计模式,其中基类的一些方法使用了它没有定义的方法,并且该方法应该由另一个基类实现,而不是像定义1中那样由派生类实现。
术语mixin类指的是打算在该设计模式中使用的基类(TODO是使用该方法的基类,还是实现该方法的基类?)
判断一个给定的类是否为mixin并不容易:方法可以只是在派生类上实现,在这种情况下,我们回到定义1。你必须考虑作者的意图。
这种模式很有趣,因为它可以用不同的基类选择重新组合功能:
class HasMethod1(object):
def method(self):
return 1
class HasMethod2(object):
def method(self):
return 2
class UsesMethod10(object):
def usesMethod(self):
return self.method() + 10
class UsesMethod20(object):
def usesMethod(self):
return self.method() + 20
class C1_10(HasMethod1, UsesMethod10): pass
class C1_20(HasMethod1, UsesMethod20): pass
class C2_10(HasMethod2, UsesMethod10): pass
class C2_20(HasMethod2, UsesMethod20): pass
assert C1_10().usesMethod() == 11
assert C1_20().usesMethod() == 21
assert C2_10().usesMethod() == 12
assert C2_20().usesMethod() == 22
# Nothing prevents implementing the method
# on the base class like in Definition 1:
class C3_10(UsesMethod10):
def method(self):
return 3
assert C3_10().usesMethod() == 13
权威的Python事件
在官方的收藏文档展上。abc的文档明确使用术语Mixin方法。
它指出,如果一个类:
实现__next__ 继承自单个类Iterator
然后该类免费获得一个__iter__ mixin方法。
因此,至少在文档的这一点上,mixin不需要多重继承,并且与定义1一致。
文档在不同的地方当然可能是矛盾的,其他重要的Python库可能在它们的文档中使用其他定义。
本页还使用了术语Set mixin,这清楚地表明像Set和Iterator这样的类可以称为mixin类。
其他语言
Ruby:很明显,mixin不需要多重继承,就像主要的参考书如Programming Ruby和The Ruby Programming Language中提到的那样 c++:设为=0的虚方法是纯虚方法。 定义1与抽象类(具有纯虚方法的类)的定义一致。 该类不能被实例化。 定义2可以通过虚拟继承实现:两个派生类的多重继承
我认为之前的回答很好地定义了mixin是什么。然而, 为了更好地理解它们,从代码/实现的角度将mixin与抽象类和接口进行比较可能是有用的:
1. 抽象类
类,该类需要包含一个或多个抽象方法 抽象类可以包含状态(实例变量)和非抽象方法
2. 接口
接口只包含抽象方法(没有非抽象方法和内部状态)
3.mixin
mixin(像接口)不包含内部状态(实例变量) mixin包含一个或多个非抽象方法(与接口不同,它们可以包含非抽象方法)
在例如Python中,这些只是约定,因为上面所有的都被定义为类。然而,抽象类、接口和mixin的共同特征是它们不应该独立存在,也就是说不应该被实例化。
大致总结一下上面所有的好答案:
States / Methods | Concrete Method | Abstract Method |
---|---|---|
Concrete State | Class | Abstract Class |
Abstract State | Mixin | Interface |
这不是一个Python的例子,但在D编程语言中,术语mixin是用来指一个以同样方式使用的结构;向类中添加一堆东西。
在D中(顺便提一下,它不做MI),这是通过将一个模板(考虑语法意识和安全宏,您将接近)插入一个作用域来完成的。这允许在类、结构、函数、模块或任何东西中的一行代码扩展为任意数量的声明。
也许举几个例子会有所帮助。
如果您正在构建一个类,并且希望它像字典一样工作,那么您可以定义所有必要的__ __方法。但这有点麻烦。作为一种替代方法,您可以只定义一些,并从UserDict继承(除了任何其他继承)。DictMixin(移动到集合。py3k中的DictMixin)。这将自动定义字典api的所有其余部分。
第二个例子:GUI工具包wxPython允许您创建具有多列的列表控件(例如,在Windows资源管理器中显示的文件)。默认情况下,这些列表相当基本。您可以添加额外的功能,例如通过单击列标题按特定列对列表进行排序的功能,可以从ListCtrl继承并添加适当的mixins。