質問

書き込みカスタムクラスでしばしば重要な同等性により、 ==!= います。Pythonでは、この実施により、 __eq____ne__ 特殊な方法です。最も簡単な方法がその場で発音を確認することがこのためには、以下の方法:

class Foo:
    def __init__(self, item):
        self.item = item

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)

いの優雅なの?だけに、これらの点は上記の使用方法の比較 __dict__s?

注意:ビットの解明が __eq____ne__ 定義されていません、この挙動:

>>> a = Foo(1)
>>> b = Foo(1)
>>> a is b
False
>>> a == b
False

それは、 a == b 評価 False だから本当に運行 a is b, は、試験のアイデンティティ(すなわち、" a 同じオブジェクトとして b?").

__eq____ne__ 定義され、この挙動は、今後):

>>> a = Foo(1)
>>> b = Foo(1)
>>> a is b
False
>>> a == b
True
役に立ちましたか?

解決

このことを考え簡単な問題:

class Number:

    def __init__(self, number):
        self.number = number


n1 = Number(1)
n2 = Number(1)

n1 == n2 # False -- oops

なので、Pythonによるデフォルトのオブジェクト識別子の比較業

id(n1) # 140400634555856
id(n2) # 140400634555920

を上書きする __eq__ 機能のように問題解決:

def __eq__(self, other):
    """Overrides the default implementation"""
    if isinstance(other, Number):
        return self.number == other.number
    return False


n1 == n2 # True
n1 != n2 # True in Python 2 -- oops, False in Python 3

Python2, 常に忘れず、オーバーライドの __ne__ 機能として、 文書 状態:

ありません包含関係の中での比較。の 真実の x==y を意味するものではありません x!=y はfalseです。そのため、この を定義する __eq__(), のあるものの定義 __ne__() その 事業者の振る舞いをします。

def __ne__(self, other):
    """Overrides the default implementation (unnecessary in Python 3)"""
    return not self.__eq__(other)


n1 == n2 # True
n1 != n2 # False

Python3, この必要が無くなって 文書 状態:

デフォルトでは、 __ne__() 代表者へ __eq__() および反転結果 ない限り、 NotImplemented.が示唆 関係の比較演算子は、例えば、真実 の (x<y or x==y) を意味するものではありません x<=y.

が解決しないすべての課題です。を追加してみましょうサブクラス:

class SubNumber(Number):
    pass


n3 = SubNumber(1)

n1 == n3 # False for classic-style classes -- oops, True for new-style classes
n3 == n1 # True
n1 != n3 # True for classic-style classes -- oops, False for new-style classes
n3 != n1 # False

注意: Python2は、二種類のクラス

  • クラシック-スタイル古いスタイル 授業では、い ない からの継承 object ととして宣言される class A:, class A(): または class A(B): 場所 B クラシック-スタイルクラス

  • 新スタイル 授業は、いからは継承し object ととして宣言される class A(object) または class A(B): 場所 B 新型クラスです。Python3には新形式クラスとして宣言される class A:, class A(object): または class A(B):.

のためのクラシック-スタイルの授業では、比較動作いメソッドを呼び出すの最初のオペランドは、新しい形式のクラスでは、常にメソッドを呼び出すのは、サブクラスのオペランド にかかわらず、オペランド.

こちらでは、場合に Number クラシック-スタイルのクラス:

  • n1 == n3 電話 n1.__eq__;
  • n3 == n1 電話 n3.__eq__;
  • n1 != n3 電話 n1.__ne__;
  • n3 != n1 電話 n3.__ne__.

Number 新型クラス:

  • n1 == n3n3 == n1 電話 n3.__eq__;
  • n1 != n3n3 != n1 電話 n3.__ne__.

の非可換性を備えた問題の ==!= 事業者のためのPythonの2クラシック-スタイルの授業を __eq____ne__ メソッドを返します NotImplemented 値がオペランドタイプには対応しておりません。の 文書 を定義する NotImplemented としての価値:

数値手法と豊かな比較方法がこの値が返される場合 な実施の運用のためのオペランドを提供する。( 通訳を試した動作、またはその他の スクフォースメンバーによっては、オペレーター.) 真値はtrueです。

この場合、オペレーターの代表者の比較動作の 反射方法その他 オペランド.の 文書 定義の反映方法として、

が入れ替わ引数のバージョンのこれらの方法を使用する 左引数のオペレーションをサポートしないもの権利 引数は);むしろ、 __lt__()__gt__() それぞれその他の 反射 __le__()__ge__() 互反射、 __eq__()__ne__() 自身のものです。

結果は以下のようなものです:

def __eq__(self, other):
    """Overrides the default implementation"""
    if isinstance(other, Number):
        return self.number == other.number
    return NotImplemented

def __ne__(self, other):
    """Overrides the default implementation (unnecessary in Python 3)"""
    x = self.__eq__(other)
    if x is not NotImplemented:
        return not x
    return NotImplemented

戻る NotImplemented 値の代わりに False あとは自分がすべきことなのだといかにも新しい形式のクラスの場合 可換性を備え==!= 事業者が望の場合はオペランドの関係(相続).

いいですか。必ずしもそうではありません。どのように多くのユニークな番号を指定いますか?

len(set([n1, n2, n3])) # 3 -- oops

セット使用のハッシュオブジェクトによるデスクトップのイベントを返しますハッシュの識別子は、オブジェクトです。んでみましょう。参照してください。:

def __hash__(self):
    """Overrides the default implementation"""
    return hash(tuple(sorted(self.__dict__.items())))

len(set([n1, n2, n3])) # 1

その結果、こんな感じになっている(見、主張の検証):

class Number:

    def __init__(self, number):
        self.number = number

    def __eq__(self, other):
        """Overrides the default implementation"""
        if isinstance(other, Number):
            return self.number == other.number
        return NotImplemented

    def __ne__(self, other):
        """Overrides the default implementation (unnecessary in Python 3)"""
        x = self.__eq__(other)
        if x is not NotImplemented:
            return not x
        return NotImplemented

    def __hash__(self):
        """Overrides the default implementation"""
        return hash(tuple(sorted(self.__dict__.items())))


class SubNumber(Number):
    pass


n1 = Number(1)
n2 = Number(1)
n3 = SubNumber(1)
n4 = SubNumber(4)

assert n1 == n2
assert n2 == n1
assert not n1 != n2
assert not n2 != n1

assert n1 == n3
assert n3 == n1
assert not n1 != n3
assert not n3 != n1

assert not n1 == n4
assert not n4 == n1
assert n1 != n4
assert n4 != n1

assert len(set([n1, n2, n3, ])) == 1
assert len(set([n1, n2, n3, n4])) == 2

他のヒント

あなたが継承して注意する必要があります:

>>> class Foo:
    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False

>>> class Bar(Foo):pass

>>> b = Bar()
>>> f = Foo()
>>> f == b
True
>>> b == f
False

このように、より厳密なタイプをチェックします:

def __eq__(self, other):
    if type(other) is type(self):
        return self.__dict__ == other.__dict__
    return False

それに加えて、あなたのアプローチは、それが特別な方法がそこにあるものだ、正常に動作します。

あなたが記述の方法は、私はいつもそれをやった方法です。それは完全に汎用的なので、あなたは常にミックスインクラスにその機能を抜け出すと、あなたはその機能が必要なクラスで、それを継承することができます。

class CommonEqualityMixin(object):

    def __eq__(self, other):
        return (isinstance(other, self.__class__)
            and self.__dict__ == other.__dict__)

    def __ne__(self, other):
        return not self.__eq__(other)

class Foo(CommonEqualityMixin):

    def __init__(self, item):
        self.item = item

未直接の答えが、それは機会に冗長退屈のビットを節約するようにタックするのに十分な関連見えました。ドキュメントからストレートカット...

<時間>

functools.total_ordering(CLS)

を一つ以上の豊富な比較の注文方法を定義するクラスを考えると、このクラスのデコレータは休息を提供するのこれが可能豊富な比較操作のすべてを指定するのに労力を簡素化:ます。

クラスは__lt__()__le__()__gt__()、又は__ge__()のいずれかを定義しなければなりません。また、クラスは__eq__()方法を提供する必要があります。

バージョン2.7の新

@total_ordering
class Student:
    def __eq__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) ==
                (other.lastname.lower(), other.firstname.lower()))
    def __lt__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) <
                (other.lastname.lower(), other.firstname.lower()))

あなたは、両方の__eq__をオーバーライドする必要があり、あなたが唯一の__ne__をオーバーライドすることができますが、これは==、!==、<、>などの結果に意義を行います__cmp__ます。

はありません オブジェクトのアイデンティティのための

isテスト。これは、aとbが同じオブジェクトへの参照を保持し、両方の場合is bは場合Trueされることを意味します。 Pythonでは、あなたは常にそれらのオブジェクトが同じメモリ位置に配置する必要が真であるために、Bであるので、本質的にするために、変数ではない実際のオブジェクト内のオブジェクトへの参照を保持します。どのようにして最も重要なのは、なぜあなたは、この動作をオーバーライドして行くのでしょうか?

編集:私はそれを避けるためのpython 3から削除された__cmp__を知りませんでした。

は、この回答から: https://stackoverflow.com/a/30676267/541136 の私は、ことを証明しているがそれは用語の__ne____eq__を定義するために正しいです - 代わりに

def __ne__(self, other):
    return not self.__eq__(other)

あなたが使用する必要があります:

def __ne__(self, other):
    return not self == other

私はを平等の(==)とのアイデンティティーの(ある)あなたが探している二つの用語があると思います。たとえばます:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> a == b
True       <-- a and b have values which are equal
>>> a is b
False      <-- a and b are not the same list object

試験は、本質的に、オブジェクトのメモリアドレスを返し、従ってオーバーロードでない組み込みの「ID()関数を使用して識別するためにテストする「」である。

しかし、クラスの等価性をテストする場合には、おそらくあなたのテストについて、もう少し厳しくし、あなただけのクラスのデータ属性を比較したい:

import types

class ComparesNicely(object):

    def __eq__(self, other):
        for key, value in self.__dict__.iteritems():
            if (isinstance(value, types.FunctionType) or 
                    key.startswith("__")):
                continue

            if key not in other.__dict__:
                return False

            if other.__dict__[key] != value:
                return False

         return True

このコードは、あなたのクラスの非機能データメンバを比較するだけでなく、何をしたい一般的であるプライベート何かをスキップします。平野古いPythonオブジェクトの場合、私は私のPOPOオブジェクトはすべて、余分な(そしてほとんどの場合、同一)のロジックの負担を運ばないので、__init__、__str__、__repr__と__eq__を実装して、基本クラスを持っています。

の代わりにサブクラス化/ミックスインを使用するので、私は一般的なクラスのデコレータを使用したい。

def comparable(cls):
    """ Class decorator providing generic comparison functionality """

    def __eq__(self, other):
        return isinstance(other, self.__class__) and self.__dict__ == other.__dict__

    def __ne__(self, other):
        return not self.__eq__(other)

    cls.__eq__ = __eq__
    cls.__ne__ = __ne__
    return cls

使用方法:

@comparable
class Number(object):
    def __init__(self, x):
        self.x = x

a = Number(1)
b = Number(1)
assert a == b
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top