什么是 mixin 以及它为什么有用?

发布于 2024-07-13 20:42:58 字数 666 浏览 6 评论 0原文

Python 编程中,Mark Lutz 提到了术语 < em>混合。 我来自 C/C++/C# 背景,之前从未听说过这个术语。 什么是混音?

阅读这个例子(我有链接到,因为它很长),我假设这是使用多重继承来扩展类而不是正确的子类化的情况。 这是正确的吗?

为什么我想这样做而不是将新功能放入子类中? 就此而言,为什么混合/多重继承方法比使用组合更好?

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

In Programming Python, Mark Lutz mentions the term mixin. I am from a C/C++/C# background and I have not heard the term before. What is a mixin?

Reading between the lines of this example (which I have linked to because it is quite long), I am presuming it is a case of using multiple inheritance to extend a class as opposed to proper subclassing. Is this right?

Why would I want to do that rather than put the new functionality into a subclass? For that matter, why would a mixin/multiple inheritance approach be better than using composition?

What separates a mixin from multiple inheritance? Is it just a matter of semantics?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

孤凫 2024-07-20 20:42:58

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

  1. 你想为一个类提供很多可选功能。
  2. 您想在许多不同的类中使用一项特定功能。

对于第一个示例,请考虑 werkzeug 的请求和响应系统。 我可以通过以下方式创建一个普通的旧请求对象:

from werkzeug import BaseRequest

class Request(BaseRequest):
    pass

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

from werkzeug import BaseRequest, AcceptMixin

class Request(AcceptMixin, BaseRequest):
    pass

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

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

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

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

A mixin is a special kind of multiple inheritance. There are two main situations where mixins are used:

  1. You want to provide a lot of optional features for a class.
  2. You want to use one particular feature in a lot of different classes.

For an example of number one, consider werkzeug's request and response system. I can make a plain old request object by saying:

from werkzeug import BaseRequest

class Request(BaseRequest):
    pass

If I want to add accept header support, I would make that

from werkzeug import BaseRequest, AcceptMixin

class Request(AcceptMixin, BaseRequest):
    pass

If I wanted to make a request object that supports accept headers, etags, authentication, and user agent support, I could do this:

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

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

The difference is subtle, but in the above examples, the mixin classes weren't made to stand on their own. In more traditional multiple inheritance, the AuthenticationMixin (for example) would probably be something more like Authenticator. That is, the class would probably be designed to stand on its own.

等你爱我 2024-07-20 20:42:58

首先,您应该注意 mixins 仅存在于多重继承语言中。 您无法在 Java 或 C# 中进行 mixin。

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

Mixin 的范围通常很窄,并且不打算扩展。

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

既然你问了,我想我应该解释为什么。 最大的好处是您不必一遍又一遍地自己做。 在 C# 中,mixin 受益最大的地方可能是 Disposal 模式。 每当您实现 IDisposable 时,您几乎总是希望遵循相同的模式,但最终您会编写并重写相同的基本代码,但有细微的变化。 如果有一个可扩展的 Disposal mixin,您可以节省大量额外的打字时间。

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

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

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

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

再次考虑一个已经实现的接口。

我个人不使用 mixin,因为我主要使用不支持它们的语言进行开发,所以我很难想出一个像样的例子来提供“啊哈!”的感觉。 属于你的时刻。 但我会再试一次。 我将使用一个人为的示例——大多数语言已经以某种方式提供了该功能——但这将有望解释如何创建和使用 mixins。 如下:

假设您有一个类型,您希望能够与 XML 进行序列化。 您希望该类型提供一个“ToXML”方法,该方法返回一个包含带有该类型数据值的 XML 片段的字符串,以及一个“FromXML”方法,该方法允许该类型从字符串中的 XML 片段重建其数据值。 同样,这是一个人为的示例,因此您可能使用文件流或语言运行时库中的 XML Writer 类...无论如何。 重点是您希望将对象序列化为 XML 并从 XML 获取一个新对象。

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

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

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

现在想象一下将此场景用于其他事情,例如创建一个 mixin 以确保每个混合它的类都记录每个方法调用,或者创建一个 mixin 为混合它的类型提供事务性。这个列表可以继续下去。

如果您只是将 mixin 视为一个小型基本类型,旨在向类型添加少量功能而不影响该类型,那么您就很成功了。

希望。 :)

First, you should note that mixins only exist in multiple-inheritance languages. You can't do a mixin in Java or C#.

Basically, a mixin is a stand-alone base type that provides limited functionality and polymorphic resonance for a child class. If you're thinking in C#, think of an interface that you don't have to actually implement because it's already implemented; you just inherit from it and benefit from its functionality.

Mixins are typically narrow in scope and not meant to be extended.

[edit -- as to why:]

I suppose I should address why, since you asked. The big benefit is that you don't have to do it yourself over and over again. In C#, the biggest place where a mixin could benefit might be from the Disposal pattern. Whenever you implement IDisposable, you almost always want to follow the same pattern, but you end up writing and re-writing the same basic code with minor variations. If there were an extendable Disposal mixin, you could save yourself a lot of extra typing.

[edit 2 -- to answer your other questions]

What separates a mixin from multiple inheritance? Is it just a matter of semantics?

Yes. The difference between a mixin and standard multiple inheritance is just a matter of semantics; a class that has multiple inheritance might utilize a mixin as part of that multiple inheritance.

The point of a mixin is to create a type that can be "mixed in" to any other type via inheritance without affecting the inheriting type while still offering some beneficial functionality for that type.

Again, think of an interface that is already implemented.

I personally don't use mixins since I develop primarily in a language that doesn't support them, so I'm having a really difficult time coming up with a decent example that will just supply that "ahah!" moment for you. But I'll try again. I'm going to use an example that's contrived -- most languages already provide the feature in some way or another -- but that will, hopefully, explain how mixins are supposed to be created and used. Here goes:

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.

The other important point in this example is that you want to do this in a generic way. You don't want to have to implement a "ToXML" and "FromXML" method for every type that you want to serialize, you want some generic means of ensuring that your type will do this and it just works. You want code reuse.

If your language supported it, you could create the XmlSerializable mixin to do your work for you. This type would implement the ToXML and the FromXML methods. It would, using some mechanism that's not important to the example, be capable of gathering all the necessary data from any type that it's mixed in with to build the XML fragment returned by ToXML and it would be equally capable of restoring that data when FromXML is called.

And.. that's it. To use it, you would have any type that needs to be serialized to XML inherit from XmlSerializable. Whenever you needed to serialize or deserialize that type, you would simply call ToXML or FromXML. In fact, since XmlSerializable is a fully-fledged type and polymorphic, you could conceivably build a document serializer that doesn't know anything about your original type, accepting only, say, an array of XmlSerializable types.

Now imagine using this scenario for other things, like creating a mixin that ensures that every class that mixes it in logs every method call, or a mixin that provides transactionality to the type that mixes it in. The list can go on and on.

If you just think of a mixin as a small base type designed to add a small amount of functionality to a type without otherwise affecting that type, then you're golden.

Hopefully. :)

离旧人 2024-07-20 20:42:58

这个答案旨在用示例解释混合,它们是:

  • 自包含:简短,不需要知道任何库来理解示例。

  • Python,而不是其他语言。

    可以理解的是,存在来自其他语言(例如 Ruby)的示例,因为该术语在这些语言中更为常见,但这是一个 Python 线程。

它还应考虑有争议的问题:

是否需要多重继承来表征 mixin?

定义

我还没有看到来自“权威”来源的引用明确说明什么是 Python 中的 mixin。

我已经看到了 mixin 的两种可能的定义(如果它们被认为与其他类似的概念(例如抽象基类)不同),并且人们并不完全同意哪一种是正确的。

不同语言之间的共识可能会有所不同。

定义1:无多重继承

mixin是一个类,该类的某些方法使用了该类中未定义的方法。

因此,该类并不意味着被实例化,而是作为基类。 否则,该实例将具有无法在不引发异常的情况下调用的方法。

一些来源添加的一个约束是该类可能不包含数据,只包含方法,但我不明白为什么这是必要的。 然而在实践中,许多有用的 mixins 没有任何数据,并且没有数据的基类使用起来更简单。

一个经典的示例是仅从 <=== 实现所有比较运算符:

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_ordering() 实现 装饰器,但这里的游戏是重新发明轮子:

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 出现

collections.abc 的官方文档 该文档明确使用术语Mixin 方法

它指出,如果一个类:

  • 实现__next__
  • 继承自单个类Iterator

,那么该类将获得一个__iter__mixin方法 免费。

因此,至少在文档的这一点上,mixin 不需要多重继承,并且与定义 1 一致。

文档当然可能在不同点上存在矛盾,并且其他重要的 Python 库可能是使用其文档中的其他定义。

此页面还使用术语 Set mixin,它清楚地表明像 SetIterator 这样的类可以称为 Mixin 类。

在其他语言中

  • Ruby:mixin 显然不需要多重继承,正如主要参考书中提到的那样,例如 Ruby 编程 和 Ruby 编程语言

  • C++:设置 =0虚拟方法是纯虚拟方法。

    定义1与抽象类(具有纯虚方法的类)的定义一致。
    该类无法实例化。

    定义 2 可以通过虚拟继承实现:来自两个派生类的多重继承

This answer aims to explain mixins with examples that are:

  • self-contained: short, with no need to know any libraries to understand the example.

  • in Python, not in other languages.

    It is understandable that there were examples from other languages such as Ruby since the term is much more common in those languages, but this is a Python thread.

It shall also consider the controversial question:

Is multiple inheritance necessary or not to characterize a mixin?

Definitions

I have yet to see a citation from an "authoritative" source clearly saying what is a mixin in Python.

I have seen 2 possible definitions of a mixin (if they are to be considered as different from other similar concepts such as abstract base classes), and people don't entirely agree on which one is correct.

The consensus may vary between different languages.

Definition 1: no multiple inheritance

A mixin is a class such that some method of the class uses a method which is not defined in the class.

Therefore the class is not meant to be instantiated, but rather serve as a base class. Otherwise the instance would have methods that cannot be called without raising an exception.

A constraint which some sources add is that the class may not contain data, only methods, but I don't see why this is necessary. In practice however, many useful mixins don't have any data, and base classes without data are simpler to use.

A classic example is the implementation of all comparison operators from only <= and ==:

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 

This particular example could have been achieved via the functools.total_ordering() decorator, but the game here was to reinvent the wheel:

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)

Definition 2: multiple inheritance

A mixin is a design pattern in which some method of a base class uses a method it does not define, and that method is meant to be implemented by another base class, not by the derived like in Definition 1.

The term mixin class refers to base classes which are intended to be used in that design pattern (TODO those that use the method, or those that implement it?)

It is not easy to decide if a given class is a mixin or not: the method could be just implemented on the derived class, in which case we're back to Definition 1. You have to consider the author's intentions.

This pattern is interesting because it is possible to recombine functionalities with different choices of base classes:

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

Authoritative Python occurrences

At the official documentatiton for collections.abc the documentation explicitly uses the term Mixin Methods.

It states that if a class:

  • implements __next__
  • inherits from a single class Iterator

then the class gets an __iter__ mixin method for free.

Therefore at least on this point of the documentation, mixin does not not require multiple inheritance, and is coherent with Definition 1.

The documentation could of course be contradictory at different points, and other important Python libraries might be using the other definition in their documentation.

This page also uses the term Set mixin, which clearly suggests that classes like Set and Iterator can be called Mixin classes.

In other languages

  • Ruby: Clearly does not require multiple inheritance for mixin, as mentioned in major reference books such as Programming Ruby and The Ruby programming Language

  • C++: A virtual method that is set =0 is a pure virtual method.

    Definition 1 coincides with the definition of an abstract class (a class that has a pure virtual method).
    That class cannot be instantiated.

    Definition 2 is possible with virtual inheritance: Multiple Inheritance from two derived classes

べ繥欢鉨o。 2024-07-20 20:42:58

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

我对管理你称之为 Mixin 的东西的约定的理解是,Mixin:

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

这样它就限制了多重继承的潜在复杂性,并且通过限制您必须查看的位置(与完整的多重继承相比),可以相当轻松地跟踪程序流程。 它们类似于 ruby 模块

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

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

I think of them as a disciplined way of using multiple inheritance - because ultimately a mixin is just another python class that (might) follow the conventions about classes that are called mixins.

My understanding of the conventions that govern something you would call a Mixin are that a Mixin:

  • adds methods but not instance variables (class constants are OK)
  • only inherits from object (in Python)

That way it limits the potential complexity of multiple inheritance, and makes it reasonably easy to track the flow of your program by limiting where you have to look (compared to full multiple inheritance). They are similar to ruby modules.

If I want to add instance variables (with more flexibility than allowed for by single inheritance) then I tend to go for composition.

Having said that, I have seen classes called XYZMixin that do have instance variables.

清浅ˋ旧时光 2024-07-20 20:42:58

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

1。 抽象类

  • 需要包含一个或多个抽象方法的类

  • 抽象类 可以包含状态(实例变量)和非抽象方法

2。 接口

  • 接口包含抽象方法(没有非抽象方法,也没有内部状态)

3。 MixIns

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

在例如Python中,这些只是约定,因为以上所有内容都被定义为。 然而,抽象类、接口MixIn的共同特征是它们不应该单独存在,即不应该被实例化。

I think previous responses defined very well what MixIns are. However,
in order to better understand them, it might be useful to compare MixIns with Abstract Classes and Interfaces from the code/implementation perspective:

1. Abstract Class

  • Class that needs to contain one or more abstract methods

  • Abstract Class can contain state (instance variables) and non-abstract methods

2. Interface

  • Interface contains abstract methods only (no non-abstract methods and no internal state)

3. MixIns

  • MixIns (like Interfaces) do not contain internal state (instance variables)
  • MixIns contain one or more non-abstract methods (they can contain non-abstract methods unlike interfaces)

In e.g. Python these are just conventions, because all of the above are defined as classes. However, the common feature of both Abstract Classes, Interfaces and MixIns is that they should not exist on their own, i.e. should not be instantiated.

青朷 2024-07-20 20:42:58

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

mixin 是多重继承的有限形式。 在某些语言中,向类添加 mixin 的机制与继承的机制略有不同(在语法方面)。

特别是在 Python 上下文中,mixin 是一个父类,它为子类提供功能,但本身并不打算实例化。

你可能会说,“这只是多重继承,而不是真正的 mixin”,因为可能会被混淆为 mixin 的类实际上可以被实例化和使用 - 所以这确实是一种语义上的、非常真实的差异。

多重继承

示例此示例来自文档, 是一个有序计数器:

类 OrderedCounter(Counter, OrderedDict): 
       “记住第一次遇到元素的顺序的计数器” 

       def __repr__(自我): 
           return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) 

       def __reduce__(自我): 
           返回 self.__class__, (Or​​deredDict(self),) 
  

它从 collections 模块中继承了 CounterOrderedDict

CounterOrderedDict 都旨在单独实例化和使用。 然而,通过对它们进行子类化,我们可以拥有一个有序的计数器并重用每个对象中的代码。

这是重用代码的有效方法,但也可能存在问题。 如果发现其中一个对象存在错误,不小心修复它可能会在子类中产生错误。

Mixin 的示例

Mixin 通常被推广为一种实现代码重用的方法,而不会出现协作多重继承(如 OrderedCounter)可能存在的潜在耦合问题。 当您使用 mixin 时,您使用的功能与数据并不紧密耦合。

与上面的示例不同,mixin 并不打算单独使用。 它提供新的或不同的功能。

例如,标准库在socketserver 库。

可以创建每种类型服务器的分叉和线程版本
使用这些混合类。 例如,ThreadingUDPServer 是
创建如下:

类 ThreadingUDPServer(ThreadingMixIn, UDPServer): 
      经过 
  

混合类首先出现,因为它重写了中定义的方法
UDP服务器。 设置各种属性也会改变
底层服务器机制。

在这种情况下,mixin 方法会覆盖 UDPServer 对象定义中的方法以允许并发。

重写的方法似乎是process_request,它还提供了另一个方法process_request_thread。 这是来自源代码

类ThreadingMixIn: 
          """混合类来处理新线程中的每个请求。""" 

          # 决定线程在终止时将如何行动 
          # 主要流程 
          daemon_threads = False 

          def process_request_thread(自身, 请求, client_address): 
              """与 BaseServer 中相同,但作为线程。 
              另外,这里还进行了异常处理。 
              ”“” 
              尝试: 
                  self.finish_request(请求,client_address) 
              除了例外: 
                  self.handle_error(请求,client_address) 
              最后: 
                  self.shutdown_request(请求) 

          def process_request(自身,请求,client_address): 
              """启动一个新线程来处理请求。""" 
              t = threading.Thread(target = self.process_request_thread, 
                                   args = (请求, 客户端地址)) 
              t.daemon = self.daemon_threads 
              t.start() 
  

一个人为的示例

这是一个 mixin,主要用于演示目的 - 大多数对象将超越此 repr 的用处:

class SimpleInitReprMixin(object):
    """mixin, don't instantiate - useful for classes instantiable
    by keyword arguments to their __init__ method.
    """
    __slots__ = () # allow subclasses to use __slots__ to prevent __dict__
    def __repr__(self):
        kwarg_strings = []
        d = getattr(self, '__dict__', None)
        if d is not None:
            for k, v in d.items():
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        slots = getattr(self, '__slots__', None)
        if slots is not None:
            for k in slots:
                v = getattr(self, k, None)
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        return '{name}({kwargs})'.format(
          name=type(self).__name__,
          kwargs=', '.join(kwarg_strings)
          )

并且用法将是:

class Foo(SimpleInitReprMixin): # add other mixins and/or extend another class here
    __slots__ = 'foo',
    def __init__(self, foo=None):
        self.foo = foo
        super(Foo, self).__init__()

并且用法:

>>> f1 = Foo('bar')
>>> f2 = Foo()
>>> f1
Foo(foo='bar')
>>> f2
Foo(foo=None)

What separates a mixin from multiple inheritance? Is it just a matter of semantics?

A mixin is a limited form of multiple inheritance. In some languages the mechanism for adding a mixin to a class is slightly different (in terms of syntax) from that of inheritance.

In the context of Python especially, a mixin is a parent class that provides functionality to subclasses but is not intended to be instantiated itself.

What might cause you to say, "that's just multiple inheritance, not really a mixin" is if the class that might be confused for a mixin can actually be instantiated and used - so indeed it is a semantic, and very real, difference.

Example of Multiple Inheritance

This example, from the documentation, is an OrderedCounter:

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'

     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

It subclasses both the Counter and the OrderedDict from the collections module.

Both Counter and OrderedDict are intended to be instantiated and used on their own. However, by subclassing them both, we can have a counter that is ordered and reuses the code in each object.

This is a powerful way to reuse code, but it can also be problematic. If it turns out there's a bug in one of the objects, fixing it without care could create a bug in the subclass.

Example of a Mixin

Mixins are usually promoted as the way to get code reuse without potential coupling issues that cooperative multiple inheritance, like the OrderedCounter, could have. When you use mixins, you use functionality that isn't as tightly coupled to the data.

Unlike the example above, a mixin is not intended to be used on its own. It provides new or different functionality.

For example, the standard library has a couple of mixins in the socketserver library.

Forking and threading versions of each type of server can be created
using these mix-in classes. For instance, ThreadingUDPServer is
created as follows:

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
    pass

The mix-in class comes first, since it overrides a method defined in
UDPServer. Setting the various attributes also changes the behavior of
the underlying server mechanism.

In this case, the mixin methods override the methods in the UDPServer object definition to allow for concurrency.

The overridden method appears to be process_request and it also provides another method, process_request_thread. Here it is from the source code:

class ThreadingMixIn:
        """Mix-in class to handle each request in a new thread."""

        # Decides how threads will act upon termination of the
        # main process
        daemon_threads = False

        def process_request_thread(self, request, client_address):
            """Same as in BaseServer but as a thread.
            In addition, exception handling is done here.
            """
            try:
                self.finish_request(request, client_address)
            except Exception:
                self.handle_error(request, client_address)
            finally:
                self.shutdown_request(request)

        def process_request(self, request, client_address):
            """Start a new thread to process the request."""
            t = threading.Thread(target = self.process_request_thread,
                                 args = (request, client_address))
            t.daemon = self.daemon_threads
            t.start()

A Contrived Example

This is a mixin that is mostly for demonstration purposes - most objects will evolve beyond the usefulness of this repr:

class SimpleInitReprMixin(object):
    """mixin, don't instantiate - useful for classes instantiable
    by keyword arguments to their __init__ method.
    """
    __slots__ = () # allow subclasses to use __slots__ to prevent __dict__
    def __repr__(self):
        kwarg_strings = []
        d = getattr(self, '__dict__', None)
        if d is not None:
            for k, v in d.items():
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        slots = getattr(self, '__slots__', None)
        if slots is not None:
            for k in slots:
                v = getattr(self, k, None)
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        return '{name}({kwargs})'.format(
          name=type(self).__name__,
          kwargs=', '.join(kwarg_strings)
          )

and usage would be:

class Foo(SimpleInitReprMixin): # add other mixins and/or extend another class here
    __slots__ = 'foo',
    def __init__(self, foo=None):
        self.foo = foo
        super(Foo, self).__init__()

And usage:

>>> f1 = Foo('bar')
>>> f2 = Foo()
>>> f1
Foo(foo='bar')
>>> f2
Foo(foo=None)
汹涌人海 2024-07-20 20:42:58

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

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

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

Mixins is a concept in Programming in which the class provides functionalities but it is not meant to be used for instantiation. Main purpose of Mixins is to provide functionalities which are standalone and it would be best if the mixins itself do not have inheritance with other mixins and also avoid state. In languages such as Ruby, there is some direct language support but for Python, there isn't. However, you could used multi-class inheritance to execute the functionality provided in Python.

I watched this video http://www.youtube.com/watch?v=v_uKI2NOLEM to understand the basics of mixins. It is quite useful for a beginner to understand the basics of mixins and how they work and the problems you might face in implementing them.

Wikipedia is still the best: http://en.wikipedia.org/wiki/Mixin

萌面超妹 2024-07-20 20:42:58

这个概念来自 Steve's Ice Cream,一家由 Steve Herrell 在萨默维尔创立的冰淇淋店1973 年,马萨诸塞州,将混合(糖果、蛋糕等)混合到基本冰淇淋口味(香草、巧克力等)中。 受到 Steve's Ice Cream 的启发,Flavors 编程语言的设计者将这一概念包含在1979 年首次成为一种编程语言,其中 mix-ins 是为增强其他类而设计的小型帮助器类,flavors 是大型独立类。

因此,这个概念的要点是可重用扩展(“可重用”相对于“一次性”;“扩展”相对于“基础”)。 混合类可以是抽象类或具体类,因为混合类具有不完整的接口,而抽象类具有不完整的实现,而具体类具有完整的实现。 混合类可以在单继承中继承,通常用于扩展类的接口,也可以在多重继承中继承,通常用于扩展超级的实现>-类。

混合类名称通常以“-MixIn”、“-able”或“-ible”为后缀,以强调其性质,就像在 Python 标准库中使用 ThreadingMixInForkingMixIn 一样socketserver 模块的 类,以及 HashableIterableCallableAwaitableAsyncIterable 和 < collections.abcReversible 类代码>模块。

以下是 collections.abc 模块的抽象混合内置类 Sized 的示例,用于单继承,用于扩展 sub< 的接口/em> - 使用 __len__ 特殊方法创建 QueueStack 类:

import abc
import collections.abc


class Queue(collections.abc.Sized, metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def enqueue(self, item):
        raise NotImplementedError

    @abc.abstractmethod
    def dequeue(self):
        raise NotImplementedError


class Stack(collections.abc.Sized, metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def push(self, item):
        raise NotImplementedError

    @abc.abstractmethod
    def pop(self):
        raise NotImplementedError

以下是具体混合类 LoggingMixIn 的示例 在多重继承中使用,用于扩展具有日志记录功能的内置超级listdict的实现:

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'

The concept comes from Steve’s Ice Cream, an ice cream store founded by Steve Herrell in Somerville, Massachusetts, in 1973, where mix-ins (candies, cakes, etc.) were mixed into basic ice cream flavors (vanilla, chocolate, etc.). Inspired by Steve’s Ice Cream, the designers of the Flavors programming language included the concept in a programming language for the first time in 1979, where mix-ins were small helper classes designed for enhancing other classes, and flavors were large standalone classes.

So the gist of the concept is a reusable extension (’reusable’ as opposed to ‘one-time’; ‘extension’ as opposed to ‘foundation’). A mix-in class can be an abstract class or concrete class since mix-in classes have incomplete interfaces whereas abstract classes have incomplete implementations and concrete classes have complete implementations. A mix-in class can be inherited from in single inheritance, usually for extending the interface of the sub-class, or in multiple inheritance, usually for extending the implementation of the super-class.

Mix-in class names are conventionally suffixed with ‘-MixIn’, ‘-able’, or ‘-ible’ to emphasize their nature, like in the Python standard library with the ThreadingMixIn and ForkingMixIn classes of the socketserver module, and the Hashable, Iterable, Callable, Awaitable, AsyncIterable, and Reversible classes of the collections.abc module.

Here is an example of the abstract mix-in built-in class Sized of the collections.abc module used in single inheritance for extending the interfaces of the sub-classes Queue and Stack with the __len__ special method:

import abc
import collections.abc


class Queue(collections.abc.Sized, metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def enqueue(self, item):
        raise NotImplementedError

    @abc.abstractmethod
    def dequeue(self):
        raise NotImplementedError


class Stack(collections.abc.Sized, metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def push(self, item):
        raise NotImplementedError

    @abc.abstractmethod
    def pop(self):
        raise NotImplementedError

Here is an example of a concrete mix-in class LoggingMixIn used in multiple inheritance for extending the implementations of the built-in super-classes list and dict with logging capability:

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'
你对谁都笑 2024-07-20 20:42:58

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

在 Scala 中,您可以按照此处所述进行 mixins,但非常有趣的是,mixins 实际上“融合”在一起以创建一种新的类来继承。 本质上,您不是从多个类/mixin 继承,而是生成一种新的类,其中包含要继承的 mixin 的所有属性。 这是有道理的,因为 Scala 基于 JVM,目前不支持多重继承(从 Java 8 开始)。 顺便说一句,这个 mixin 类类型是 Scala 中称为 Trait 的特殊类型。

它以类的定义方式暗示:
NewClass 类扩展了 FirstMixin、SecondMixin 和 ThirdMixin
...

我不确定 CPython 解释器是否做同样的事情(混合类组合),但我不会感到惊讶。 另外,由于具有 C++ 背景,我不会将 ABC 或“接口”称为等同于 mixin —— 这是一个类似的概念,但在使用和实现上有所不同。

I think there have been some good explanations here but I wanted to provide another perspective.

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.

It's hinted at in the way a class is defined:
class NewClass extends FirstMixin with SecondMixin with ThirdMixin
...

I'm not sure if the CPython interpreter does the same (mixin class-composition) but I wouldn't be surprised. Also, coming from a C++ background, I would not call an ABC or 'interface' equivalent to a mixin -- it's a similar concept but divergent in use and implementation.

沫尐诺 2024-07-20 20:42:58

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

如果您正在构建一个类并且希望它像字典一样工作,则可以定义所有必要的各种 __ __ 方法。 但这有点痛苦。 作为替代方案,您可以只定义一些,并从 UserDict.DictMixin 继承(除了任何其他继承之外)(在 py3k 中移至 collections.DictMixin)。 这将具有自动定义字典 ​​api 的所有其余部分的效果。

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

Perhaps a couple of examples will help.

If you're building a class and you want it to act like a dictionary, you can define all the various __ __ methods necessary. But that's a bit of a pain. As an alternative, you can just define a few, and inherit (in addition to any other inheritance) from UserDict.DictMixin (moved to collections.DictMixin in py3k). This will have the effect of automatically defining all the rest of the dictionary api.

A second example: the GUI toolkit wxPython allows you to make list controls with multiple columns (like, say, the file display in Windows Explorer). By default, these lists are fairly basic. You can add additional functionality, such as the ability to sort the list by a particular column by clicking on the column header, by inheriting from ListCtrl and adding appropriate mixins.

殊姿 2024-07-20 20:42:58

这不是一个 Python 示例,而是在 D 编程语言 中,术语 mixin 用于引用经常使用的构造一样的方法; 向类中添加一堆东西。

在 D 中(顺便说一句,它不执行 MI),这是通过将模板(考虑语法感知和安全的宏,你会接近)插入范围来完成的。 这允许类、结构、函数、模块或任何内容中的一行代码扩展到任意数量的声明。

It's not a Python example but in the D programing language the term mixin is used to refer to a construct used much the same way; adding a pile of stuff to a class.

In D (which by the way doesn't do MI) this is done by inserting a template (think syntactically aware and safe macros and you will be close) into a scope. This allows for a single line of code in a class, struct, function, module or whatever to expand to any number of declarations.

魂归处 2024-07-20 20:42:58

OP 提到他/她从未听说过 C++ 中的 mixin,也许这是因为它们在 C++ 中被称为好奇重复模板模式 (CRTP)。 另外,@Ciro Santilli 提到 mixin 是通过 C++ 中的抽象基类实现的。 虽然抽象基类可以用来实现 mixin,但它是一种矫枉过正,因为运行时虚函数的功能可以在编译时使用模板来实现,而无需在运行时查找虚表的开销。

CRTP模式在此处有详细描述,

我已将@Ciro Santilli的答案中的python示例转换为C++使用下面的模板类:

    #include <iostream>
    #include <assert.h>

    template <class T>
    class ComparableMixin {
    public:
        bool operator !=(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) == static_cast<T&>(other));
        }
        bool operator <(ComparableMixin &other) {
            return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
        }
        bool operator >(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
        }
        bool operator >=(ComparableMixin &other) {
            return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
        }
        protected:
            ComparableMixin() {}
    };

    class Integer: public ComparableMixin<Integer> {
    public:
     Integer(int i) {
         this->i = i;
     }
     int i;
     bool operator <=(Integer &other) {
         return (this->i <= other.i);
     }
     bool operator ==(Integer &other) {
         return (this->i == other.i);
     }
    };

int main() {

    Integer i(0) ;
    Integer j(1) ;
    //ComparableMixin<Integer> c; // this will cause compilation error because constructor is protected.
    assert (i < j );
    assert (i != j);
    assert (j >  i);
    assert (j >= i);

    return 0;
}

编辑:在 ComparableMixin 中添加受保护的构造函数,以便它只能继承而不能实例化。 更新了示例以显示创建 ComparableMixin 对象时受保护的构造函数将如何导致编译错误。

OP mentioned that he/she never heard of mixin in C++, perhaps that is because they are called Curiously Recurring Template Pattern (CRTP) in C++. Also, @Ciro Santilli mentioned that mixin is implemented via abstract base class in C++. While abstract base class can be used to implement mixin, it is an overkill as the functionality of virtual function at run-time can be achieved using template at compile time without the overhead of virtual table lookup at run-time.

The CRTP pattern is described in detail here

I have converted the python example in @Ciro Santilli's answer into C++ using template class below:

    #include <iostream>
    #include <assert.h>

    template <class T>
    class ComparableMixin {
    public:
        bool operator !=(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) == static_cast<T&>(other));
        }
        bool operator <(ComparableMixin &other) {
            return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
        }
        bool operator >(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
        }
        bool operator >=(ComparableMixin &other) {
            return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
        }
        protected:
            ComparableMixin() {}
    };

    class Integer: public ComparableMixin<Integer> {
    public:
     Integer(int i) {
         this->i = i;
     }
     int i;
     bool operator <=(Integer &other) {
         return (this->i <= other.i);
     }
     bool operator ==(Integer &other) {
         return (this->i == other.i);
     }
    };

int main() {

    Integer i(0) ;
    Integer j(1) ;
    //ComparableMixin<Integer> c; // this will cause compilation error because constructor is protected.
    assert (i < j );
    assert (i != j);
    assert (j >  i);
    assert (j >= i);

    return 0;
}

EDIT: Added protected constructor in ComparableMixin so that it can only be inherited and not instantiated. Updated the example to show how protected constructor will cause compilation error when an object of ComparableMixin is created.

蒗幽 2024-07-20 20:42:58

我建议不要在新的 Python 代码中混合,如果你能找到任何其他方法(例如组合而不是继承,或者只是将猴子修补方法到你自己的类中),那也没什么了不起的努力。

在旧式类中,您可以使用混合作为从另一个类获取一些方法的方式。 但在新风格的世界中,一切,甚至混合,都继承自object。 这意味着任何多重继承的使用都会自然地引入 MRO 问题

有多种方法可以使多重继承 MRO 在 Python 中工作,最显着的是 super() 函数,但这意味着您必须使用 super() 来完成整个类层次结构,并且理解控制流要困难得多。

I'd advise against mix-ins in new Python code, if you can find any other way around it (such as composition-instead-of-inheritance, or just monkey-patching methods into your own classes) that isn't much more effort.

In old-style classes you could use mix-ins as a way of grabbing a few methods from another class. But in the new-style world everything, even the mix-in, inherits from object. That means that any use of multiple inheritance naturally introduces MRO issues.

There are ways to make multiple-inheritance MRO work in Python, most notably the super() function, but it means you have to do your whole class hierarchy using super(), and it's considerably more difficult to understand the flow of control.

半夏半凉 2024-07-20 20:42:58

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 gives a way to add functionality in a class, i.e you can interact with methods defined in a module by including the module inside the desired class. Though ruby doesn't supports multiple inheritance but provides mixin as an alternative to achieve that.

here is an example that explains how multiple inheritance is achieved using 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
不疑不惑不回忆 2024-07-20 20:42:58

我刚刚使用 python mixin 来实现 python milters 的单元测试。 通常,milter 会与 MTA 进行通信,这使得单元测试变得困难。 测试 mixin 会覆盖与 MTA 对话的方法,并创建一个由测试用例驱动的模拟环境。

因此,您采用未修改的 milter 应用程序(例如 spfmilter)并混合 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='[email protected]')
  self.assertEqual(rc,Milter.CONTINUE)
  milter.close()

http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?修订版=1.6&视图=标记

I just used a python mixin to implement unit testing for python milters. Normally, a milter talks to an MTA, making unit testing difficult. The test mixin overrides methods that talk to the MTA, and create a simulated environment driven by test cases instead.

So, you take an unmodified milter application, like spfmilter, and mixin TestBase, like this:

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)

Then, use TestMilter in the test cases for the milter application:

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='[email protected]')
  self.assertEqual(rc,Milter.CONTINUE)
  milter.close()

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

七度光 2024-07-20 20:42:58

也许 ruby​​ 的一个示例可以提供帮助:

您可以包含 mixin Comparable 并定义一个函数 "<=>(other)",mixin 提供所有这些函数:

<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)

它通过调用 <=>(other) 并返回正确的结果来实现此目的。

如果两个对象相等,"instance <=> other" 返回 0;如果 instance 大于 other 且大于 other,则返回小于 0如果 other 更大,则为 0。

Maybe an example from ruby can help:

You can include the mixin Comparable and define one function "<=>(other)", the mixin provides all those functions:

<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)

It does this by invoking <=>(other) and giving back the right result.

"instance <=> other" returns 0 if both objects are equal, less than 0 if instance is bigger than other and more than 0 if other is bigger.

芸娘子的小脾气 2024-07-20 20:42:58

粗略总结一下上面的所有精彩答案:

           状态  /     方法具体方法抽象方法
具体状态抽象类
抽象状态Mixin接口

Roughly summarizing all great answers above:

                States        /     MethodsConcrete MethodAbstract Method
Concrete StateClassAbstract Class
Abstract StateMixinInterface
薔薇婲 2024-07-20 20:42:58

我听说你有 ac# 背景。 因此,.NET 的 mixin 实现可能是一个好的起点。

您可能想查看 codeplex 项目,网址为 http://remix.codeplex.com/

观看语言。 net 研讨会链接以获取概述。 codeplex 页面上的文档还有更多内容。

问候
斯特凡

I read that you have a c# background. So a good starting point might be a mixin implementation for .NET.

You might want to check out the codeplex project at http://remix.codeplex.com/

Watch the lang.net Symposium link to get an overview. There is still more to come on documentation on codeplex page.

regards
Stefan

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文