在Python编程中,Mark Lutz提到了术语mixin。我有C/ c++ / c#的背景,以前没有听说过这个术语。什么是mixin?
从这个例子的字里行间(我链接了这个例子,因为它很长),我假设这是一个使用多重继承来扩展类的情况,而不是适当的子类化。这样对吗?
为什么我要这样做,而不是把新功能放到一个子类?就此而言,为什么混合/多重继承方法会比使用组合更好呢?
mixin与多重继承的区别是什么?这只是语义上的问题吗?
在Python编程中,Mark Lutz提到了术语mixin。我有C/ c++ / c#的背景,以前没有听说过这个术语。什么是mixin?
从这个例子的字里行间(我链接了这个例子,因为它很长),我假设这是一个使用多重继承来扩展类的情况,而不是适当的子类化。这样对吗?
为什么我要这样做,而不是把新功能放到一个子类?就此而言,为什么混合/多重继承方法会比使用组合更好呢?
mixin与多重继承的区别是什么?这只是语义上的问题吗?
当前回答
首先,您应该注意,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视为一个小型的基本类型,用于在不影响类型的情况下向类型添加少量功能,那么您就很好了。
希望。:)
其他回答
首先,您应该注意,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视为一个小型的基本类型,用于在不影响类型的情况下向类型添加少量功能,那么您就很好了。
希望。:)
我认为这里有一些很好的解释,但我想提供另一个角度。
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——它们是类似的概念,但在使用和实现上有所不同。
这不是一个Python的例子,但在D编程语言中,术语mixin是用来指一个以同样方式使用的结构;向类中添加一堆东西。
在D中(顺便提一下,它不做MI),这是通过将一个模板(考虑语法意识和安全宏,您将接近)插入一个作用域来完成的。这允许在类、结构、函数、模块或任何东西中的一行代码扩展为任意数量的声明。
这个概念来自Steve 's Ice Cream,这是一家由Steve Herrell于1973年在马萨诸塞州萨默维尔创立的冰淇淋店,在那里混合(糖果、蛋糕等)被混合成基本的冰淇淋口味(香草、巧克力等)。
受到Steve 's Ice Cream的启发,Lisp对象系统Flavors的设计者第一次在编程语言中包含了这个概念,其中mix-in是用于增强其他类的小型辅助类,flavour是大型独立类。
因此,主要的思想是mix-in是一个可重用的扩展(“可重用”而不是“独占”;' extension '而不是' base ')。
这个概念与单一或多个继承以及抽象或具体类的概念是正交的。混合类可以用于单个或多个继承,可以是抽象类也可以是具体类。混合类有不完整的接口,抽象类有不完整的实现,具体类有完整的实现。
Mix-in类名通常以' -MixIn '、' -able '或' -ible '作为后缀,以强调它们的性质,就像Python标准库中socketserver模块的ThreadingMixIn和ForkingMixIn类,以及集合的Hashable、Iterable、Callable、Awaitable、AsyncIterable和可逆类一样。美国广播公司(abc)模块。
下面是一个mix-in类的例子,用于扩展Python内置list和dict类的日志记录功能:
import logging
class LoggingMixIn:
def __setitem__(self, key, value):
logging.info('Setting %r to %r', key, value)
super().__setitem__(key, value)
def __delitem__(self, key):
logging.info('Deleting %r', key)
super().__delitem__(key)
class LoggingList(LoggingMixIn, list):
pass
class LoggingDict(LoggingMixIn, dict):
pass
>>> logging.basicConfig(level=logging.INFO)
>>> l = LoggingList([False])
>>> d = LoggingDict({'a': False})
>>> l[0] = True
INFO:root:Setting 0 to True
>>> d['a'] = True
INFO:root:Setting 'a' to True
>>> del l[0]
INFO:root:Deleting 0
>>> del d['a']
INFO:root:Deleting 'a'
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。也就是说,这个类可能被设计成独立存在的。