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

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

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

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


当前回答

也许举几个例子会有所帮助。

如果您正在构建一个类,并且希望它像字典一样工作,那么您可以定义所有必要的__ __方法。但这有点麻烦。作为一种替代方法,您可以只定义一些,并从UserDict继承(除了任何其他继承)。DictMixin(移动到集合。py3k中的DictMixin)。这将自动定义字典api的所有其余部分。

第二个例子:GUI工具包wxPython允许您创建具有多列的列表控件(例如,在Windows资源管理器中显示的文件)。默认情况下,这些列表相当基本。您可以添加额外的功能,例如通过单击列标题按特定列对列表进行排序的功能,可以从ListCtrl继承并添加适当的mixins。

其他回答

我认为它们是使用多重继承的一种有纪律的方式——因为最终mixin只是另一个python类,它(可能)遵循称为mixin的类的约定。

我对Mixin的理解是:

添加方法但不添加实例变量(类常量是可以的) 仅从object继承(Python中)

通过这种方式,它限制了多重继承的潜在复杂性,并通过限制必须查看的位置(与完整的多重继承相比)使跟踪程序流程变得相当容易。它们类似于ruby模块。

如果我想添加实例变量(具有比单继承所允许的更大的灵活性),那么我倾向于组合。

话虽如此,我还见过名为XYZMixin的类确实有实例变量。

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。也就是说,这个类可能被设计成独立存在的。

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

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

首先,您应该注意,mixin只存在于多继承语言中。你不能在Java或c#中做mixin。

基本上,mixin是一个独立的基类型,为子类提供有限的功能和多态共振。如果你在用c#思考,考虑一个你不需要实际实现的接口,因为它已经实现了;你只是继承了它,并从它的功能中受益。

mixin的范围通常很窄,不需要扩展。

[编辑——至于为什么:]

既然你问了,我想我该解释一下原因。最大的好处是你不需要自己一遍又一遍地做。在c#中,mixin最大的好处可能来自于处置模式。无论何时实现IDisposable,您几乎总是希望遵循相同的模式,但最终要编写和重写相同的基本代码,只是略有变化。如果有一个可扩展的处置mixin,您可以节省大量额外的输入。

[编辑2 -回答你的其他问题]

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

是的。mixin和标准多重继承之间的区别只是语义上的问题;具有多重继承的类可以利用mixin作为多重继承的一部分。

mixin的目的是创建一个可以通过继承“混合”到任何其他类型的类型,而不影响继承类型,同时仍然为该类型提供一些有益的功能。

同样,考虑一个已经实现的接口。

我个人不使用mixins,因为我主要是用一种不支持mixins的语言开发的,所以我很难想出一个像样的例子来为您提供“啊哈!”的时刻。但我会再试一次。我将使用一个人为设计的示例——大多数语言已经以某种方式提供了该特性——但希望这将解释mixin应该如何创建和使用。是:

Suppose you have a type that you want to be able to serialize to and from XML. You want the type to provide a "ToXML" method that returns a string containing an XML fragment with the data values of the type, and a "FromXML" that allows the type to reconstruct its data values from an XML fragment in a string. Again, this is a contrived example, so perhaps you use a file stream, or an XML Writer class from your language's runtime library... whatever. The point is that you want to serialize your object to XML and get a new object back from XML.

本例中另一个重要的一点是,您希望以通用的方式执行此操作。你不希望为你想要序列化的每一个类型都实现一个“ToXML”和“FromXML”方法,你需要一些通用的方法来确保你的类型能够做到这一点,并且它只是工作。您希望代码重用。

如果您的语言支持它,您可以创建XmlSerializable mixin来完成您的工作。这种类型将实现ToXML和FromXML方法。它将使用一些对示例不重要的机制,能够从混合在其中的任何类型收集所有必要的数据,以构建由ToXML返回的XML片段,并且在调用FromXML时同样能够恢复该数据。

和. .就是这样。要使用它,您需要从XmlSerializable继承任何需要序列化为XML的类型。每当需要序列化或反序列化该类型时,只需调用ToXML或FromXML即可。事实上,由于XmlSerializable是一种成熟的多态类型,因此可以想象,您可以构建一个文档序列化器,它对原始类型一无所知,只接受一个XmlSerializable类型数组。

现在想象一下将这个场景用于其他事情,比如创建一个mixin,以确保每个混合它的类都记录每个方法调用,或者为混合它的类型提供事务性的mixin。这样的例子不胜枚举。

如果您只是将mixin视为一个小型的基本类型,用于在不影响类型的情况下向类型添加少量功能,那么您就很好了。

希望。:)

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

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