web-dev-qa-db-ja.com

Python 3 for Python 2の場合)で__cmp__メソッドを使用できないのはなぜですか?

次のコード

class point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def dispc(self):
        return ('(' + str(self.x) + ',' + str(self.y) + ')')

    def __cmp__(self, other):
        return ((self.x > other.x) and (self.y > other.y))

Python 2では正常に動作しますが、Python 3ではエラーが発生します。

>>> p=point(2,3)
>>> q=point(3,4)
>>> p>q
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: point() > point()

==および!=

43
user1065734

Python 3、つまり __lt____gt____le____ge____eq__ 、および __ne__ 。参照: PEP 207-豊富な比較

__cmp__noより長く使用されています。


すなわち、 __lt__selfおよびotherを引数として取り、selfotherより小さいかどうかを返す必要があります。例えば:

class Point(object):
    ...
    def __lt__(self, other):
        return ((self.x < other.x) and (self.y < other.y))

(これは賢明な比較の実装ではありませんが、何をしようとしていたのかを理解するのは困難です。)

したがって、次のような状況の場合:

p1 = Point(1, 2)
p2 = Point(3, 4)

p1 < p2

これは次と同等です。

p1.__lt__(p2)

これはTrueを返します。

__eq__は、ポイントが等しい場合はTrueを返し、そうでない場合はFalseを返します。他の方法も同様に機能します。


functools.total_ordering デコレータ。実装する必要があるのは、たとえば__lt__および__eq__メソッド:

from functools import total_ordering

@total_ordering
class Point(object):
    def __lt__(self, other):
        ...

    def __eq__(self, other):
        ...
59
Jesse Dhillon

これは、Python 3. 3の大幅かつ意図的な変更でした。詳細については、 ここ を参照してください。

  • 順序付け比較演算子(_<_、_<=_、_>=_、_>_)は、オペランドに意味のある自然な順序付けがない場合、TypeError例外を発生させます。したがって、_1 < ''_、_0 > None_、_len <= len_などの式は無効になりました。 _None < None_はTypeErrorを返す代わりにFalseを発生させます。当然の結果として、異種混合リストをソートすることはもはや意味がありません。すべての要素は互いに比較可能でなければなりません。これは_==_演算子と_!=_演算子には適用されないことに注意してください。異なる比較できない型のオブジェクトは常に互いに等しくありません。
  • builtin.sorted()およびlist.sort()は、比較関数を提供するcmp引数を受け入れなくなりました。代わりにkey引数を使用してください。 N.B. keyおよびreverse引数は「キーワードのみ」になりました。
  • cmp()関数は存在しないものとして扱う必要があり、__cmp__()特殊メソッドはサポートされなくなりました。並べ替えには__lt__()を使用し、必要に応じて__eq__()__hash__()とともに使用し、その他の豊富な比較を行います。 (cmp()機能が本当に必要な場合は、cmp(a, b)と同等の式として_(a > b) - (a < b)_を使用できます。)
13
Ned Deily

Python3では、6つの豊富な比較演算子

__lt__(self, other) 
__le__(self, other) 
__eq__(self, other) 
__ne__(self, other) 
__gt__(self, other) 
__ge__(self, other) 

個別に提供する必要があります。これは、functools.total_orderingを使用して短縮できます。

しかし、これはほとんどの場合、かなり読みにくく、実用的ではありません。それでも同様のコードを2つの関数に入れる必要があります-または、さらにヘルパー関数を使用する必要があります。

そのため、主に以下に示すPY3__cmp__のミックスインクラスを使用することを好みます。これにより、単一の__cmp__メソッドフレームワークが再確立されます。これは、ほとんどの場合、非常に明確で実用的でした。選択したリッチ比較をオーバーライドできます。

あなたの例は次のようになります:

 class point(PY3__cmp__):
      ... 
      # unchanged code

PY3__cmp__ mixinクラス:

PY3 = sys.version_info[0] >= 3
if PY3:
    def cmp(a, b):
        return (a > b) - (a < b)
    # mixin class for Python3 supporting __cmp__
    class PY3__cmp__:   
        def __eq__(self, other):
            return self.__cmp__(other) == 0
        def __ne__(self, other):
            return self.__cmp__(other) != 0
        def __gt__(self, other):
            return self.__cmp__(other) > 0
        def __lt__(self, other):
            return self.__cmp__(other) < 0
        def __ge__(self, other):
            return self.__cmp__(other) >= 0
        def __le__(self, other):
            return self.__cmp__(other) <= 0
else:
    class PY3__cmp__:
        pass
8
kxr