在Python编程中,Mark Lutz提到了术语mixin。我有C/ c++ / c#的背景,以前没有听说过这个术语。什么是mixin?

从这个例子的字里行间(我链接了这个例子,因为它很长),我假设这是一个使用多重继承来扩展类的情况,而不是适当的子类化。这样对吗?

为什么我要这样做,而不是把新功能放到一个子类?就此而言,为什么混合/多重继承方法会比使用组合更好呢?

mixin与多重继承的区别是什么?这只是语义上的问题吗?


当前回答

我读到你有c#背景。因此,一个好的起点可能是。net的mixin实现。

你可能想在http://remix.codeplex.com/上查看codeplex项目

请观看lang.net Symposium链接以获得概述。codeplex页面上还有更多的文档。

问候 斯特凡

其他回答

我只是使用一个python mixin来实现python milters的单元测试。通常情况下,milter会与MTA交谈,这使得单元测试变得困难。测试mixin覆盖了与MTA对话的方法,并创建了一个由测试用例驱动的模拟环境。

所以,你使用一个未修改的milter应用程序,比如spfmilter,然后mixin TestBase,像这样:

class TestMilter(TestBase,spfmilter.spfMilter):
  def __init__(self):
    TestBase.__init__(self)
    spfmilter.config = spfmilter.Config()
    spfmilter.config.access_file = 'test/access.db'
    spfmilter.spfMilter.__init__(self)

然后,在milter应用程序的测试用例中使用TestMilter:

def testPass(self):
  milter = TestMilter()
  rc = milter.connect('mail.example.com',ip='192.0.2.1')
  self.assertEqual(rc,Milter.CONTINUE)
  rc = milter.feedMsg('test1',sender='good@example.com')
  self.assertEqual(rc,Milter.CONTINUE)
  milter.close()

http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup

这个答案旨在通过以下例子解释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提供了一种在类中添加功能的方法,即您可以通过将模块包含在所需的类中来与模块中定义的方法进行交互。虽然ruby不支持多重继承,但提供了mixin作为实现这一目标的替代方案。

下面是一个示例,说明如何使用mixin实现多重继承。

module A    # you create a module
    def a1  # lets have a method 'a1' in it
    end
    def a2  # Another method 'a2'
    end
end

module B    # let's say we have another module
    def b1  # A method 'b1'
    end
    def b2  #another method b2
    end
end

class Sample    # we create a class 'Sample'
    include A   # including module 'A' in the class 'Sample' (mixin)
    include B   # including module B as well

    def S1      #class 'Sample' contains a method 's1'
    end
end

samp = Sample.new    # creating an instance object 'samp'

# we can access methods from module A and B in our class(power of mixin)

samp.a1     # accessing method 'a1' from module A
samp.a2     # accessing method 'a2' from module A
samp.b1     # accessing method 'b1' from module B
samp.b2     # accessing method 'a2' from module B
samp.s1     # accessing method 's1' inside the class Sample

Mixins是编程中的一个概念,其中类提供功能,但并不用于实例化。Mixins的主要目的是提供独立的功能,最好是Mixins本身没有与其他Mixins的继承,并且避免状态。在Ruby等语言中,有一些直接的语言支持,但对于Python则没有。但是,您可以使用多类继承来执行Python中提供的功能。

我看了这个视频http://www.youtube.com/watch?v=v_uKI2NOLEM来了解mixin的基础知识。对于初学者来说,了解mixin的基础知识、它们的工作原理以及在实现它们时可能遇到的问题是非常有用的。

维基百科仍然是最好的:http://en.wikipedia.org/wiki/Mixin

大致总结一下上面所有的好答案:

                States        /     Methods Concrete Method Abstract Method
Concrete State Class Abstract Class
Abstract State Mixin Interface