この回答は、次の例を使用してミックスインを説明することを目的としています。
それは論争の的となる質問も考慮しなければならない:
ミックスインを特徴付けるために多重継承が必要ですか?
定義
Pythonのミックスインとは何かを明確に述べている「権威ある」情報源からの引用はまだ見ていません。
私はミックスインの2つの可能な定義を見ました(それらが抽象的な基本クラスのような他の同様の概念と異なると見なされる場合)、そして人々はどちらが正しいかについて完全に同意しません。
コンセンサスは言語によって異なる場合があります。
定義1:多重継承なし
ミックスインは、クラスの一部のメソッドがクラスで定義されていないメソッドを使用するようなクラスです。
したがって、クラスはインスタンス化されることを意図しておらず、基本クラスとして機能します。それ以外の場合、インスタンスには、例外を発生させずに呼び出すことができないメソッドがあります。
一部のソースが追加する制約は、クラスにはデータのみが含まれ、メソッドのみが含まれる可能性があることですが、これが必要な理由はわかりません。ただし、実際には、多くの便利なミックスインにはデータがなく、データのない基本クラスの方が使いやすくなっています。
古典的な例は、<=
とからのすべての比較演算子の実装です==
。
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:多重継承
ミックスインは、基本クラスの一部のメソッドが定義していないメソッドを使用する設計パターンであり、そのメソッドは、定義1のような派生クラスではなく、別の基本クラスによって実装されることを意図しています。
ミックスインクラスという用語は、そのデザインパターンで使用することを目的とする基本クラスを指します(メソッドを使用するものか、それを実装するものか?)
特定のクラスがミックスインであるかどうかを判断するのは簡単ではありません。メソッドを派生クラスに実装するだけの場合もあります。その場合は、定義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は多重継承を必要とせず、定義1と一貫しています。
もちろん、ドキュメントは異なる点で矛盾する可能性があり、他の重要なPythonライブラリは、ドキュメントの他の定義を使用している可能性があります。
このページでは、という用語も使用しています。これSet mixin
は、クラスがMixinクラスのようでSet
あり、Iterator
Mixinクラスと呼ぶことができることを明確に示唆しています。
他の言語で
Ruby:プログラミングRubyやRubyプログラミング言語などの主要な参考書で述べられているように、ミックスインに多重継承を必要としないことは明らかです。
C ++:実装されていないメソッドは、純粋な仮想メソッドです。
定義1は、抽象クラス(純粋な仮想メソッドを持つクラス)の定義と一致します。そのクラスはインスタンス化できません。
定義2は仮想継承で可能です。2つの派生クラスからの多重継承