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

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

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

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


当前回答

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

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

其他回答

我认为这里有一些很好的解释,但我想提供另一个角度。

In Scala, you can do mixins as has been described here but what is very interesting is that the mixins are actually 'fused' together to create a new kind of class to inherit from. In essence, you do not inherit from multiple classes/mixins, but rather, generate a new kind of class with all the properties of the mixin to inherit from. This makes sense since Scala is based on the JVM where multiple-inheritance is not currently supported (as of Java 8). This mixin class type, by the way, is a special type called a Trait in Scala.

它在定义类的方式中有所暗示: NewClass用SecondMixin和ThirdMixin扩展了FirstMixin …

我不确定CPython解释器是否做同样的事情(mixin class-composition),但我不会感到惊讶。同样,作为c++背景,我不会将ABC或“接口”称为等同于mixin——它们是类似的概念,但在使用和实现上有所不同。

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

我认为之前的回答很好地定义了mixin是什么。然而, 为了更好地理解它们,从代码/实现的角度将mixin与抽象类和接口进行比较可能是有用的:

1. 抽象类

类,该类需要包含一个或多个抽象方法 抽象类可以包含状态(实例变量)和非抽象方法

2. 接口

接口只包含抽象方法(没有非抽象方法和内部状态)

3.mixin

mixin(像接口)不包含内部状态(实例变量) mixin包含一个或多个非抽象方法(与接口不同,它们可以包含非抽象方法)

在例如Python中,这些只是约定,因为上面所有的都被定义为类。然而,抽象类、接口和mixin的共同特征是它们不应该独立存在,也就是说不应该被实例化。

mixin是一种特殊的多重继承。使用mixin的主要情况有两种:

您希望为类提供大量可选特性。 你想在很多不同的类中使用一个特定的特性。

对于第一个例子,考虑werkzeug的请求和响应系统。我可以这样创建一个普通的request对象:

from werkzeug import BaseRequest

class Request(BaseRequest):
    pass

如果我想添加接受报头支持,我会这样做

from werkzeug import BaseRequest, AcceptMixin

class Request(AcceptMixin, BaseRequest):
    pass

如果我想让一个请求对象支持接受头,标签,身份验证和用户代理支持,我可以这样做:

from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin

class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
    pass

区别是微妙的,但是在上面的例子中,mixin类并不是独立存在的。在更传统的多重继承中,AuthenticationMixin(例如)可能更像Authenticator。也就是说,这个类可能被设计成独立存在的。

这不是一个Python的例子,但在D编程语言中,术语mixin是用来指一个以同样方式使用的结构;向类中添加一堆东西。

在D中(顺便提一下,它不做MI),这是通过将一个模板(考虑语法意识和安全宏,您将接近)插入一个作用域来完成的。这允许在类、结构、函数、模块或任何东西中的一行代码扩展为任意数量的声明。