8

私は小さなヘルパークラスを持っています:

class AnyOf(object):
    def __init__(self, *args):
        self.elements = args
    def __eq__(self, other):
        return other in self.elements

これにより、次のような甘い魔法を実行できます。

>>> arr = np.array([1,2,3,4,5])
>>> arr == AnyOf(2,3)
np.array([False, True, True, False, False])

( のように) リスト内包表記を使用する必要はありませnp.array(x in (2,3) for x in arrん。

(私は、(信頼できる) ユーザーが任意のコードを入力できるようにする UI を維持しており、a == AnyOf(1,2,3)技術に詳しくないユーザーにとっては、リストの理解よりもはるかに受け入れやすいものです。)

でも!

これは一方向にしか機能しません。たとえば、AnyOf(2,3) == arrそうすると、AnyOfクラスの__eq__メソッドが呼び出されることはありません。代わりに、NumPy 配列のメソッドが呼び出され、内部的に (推測すると思いますが)そのすべての要素の__eq__メソッドが呼び出されます。__eq__

これは私を疑問に思いました: なぜ Python は右辺の同等物を許可しないの__eq__ですか? __radd__( 、 などのメソッドとほぼ同等__rmul__です。)

4

3 に答える 3

2

これは、データ モデルに関するドキュメントです。

これらのメソッドには、引数を交換したバージョンはありません (左の引数が操作をサポートしていないが、右の引数が操作をサポートしている場合に使用されます)。むしろ、__lt__()__gt__()はお互いの反映であり、__le__()__ge__()はお互いの反映であり、 __eq__()__ne__()は自分自身の反映です。オペランドが異なる型であり、右側のオペランドの型が左側のオペランドの型の直接または間接のサブクラスである場合、右側のオペランドの反映されたメソッドが優先されます。それ以外の場合、左側のオペランドのメソッドが優先されます。仮想サブクラス化は考慮されていません。

上記のコメントで述べたように、必要なものは機能__eq__し、潜在的なものと本質的に同じです。左側のオブジェクトが返される場合、__req__右側で呼び出されます:==NotImplemented

In [1]: class A:
   ...:     def __eq__(self, other):
   ...:         return NotImplemented
   ...:     

In [2]: class B:
   ...:     def __eq__(self, other): 
   ...:         print("B comparing")
   ...:         return True
   ...:     

In [3]: B() == A()
B comparing
Out[3]: True

In [4]: A() == B()
B comparing
Out[4]: True

In [5]: A() == A()
Out[5]: False

それが来るように、それは他の普通のオブジェクトでも動作します:

In [10]: 5 == B()
B comparing
Out[10]: True

ただし、一部のオブジェクトは、 or__eq__を返す代わりにon で TypeError を生成する場合があり、これはすべての種類のオブジェクトに対して信頼できるものではありません。NotImplementedFalse

あなたの場合に起こることは、独自のメソッドin 内で配列とタプルを使用して演算子を誤って使用することです。__eq__(ここの別の回答でこれを見つけてくれた@wimに感謝します)。

于 2017-11-30T16:14:25.913 に答える