次のコード
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()
==
および!=
。
Python 3、つまり __lt__
、 __gt__
、 __le__
、 __ge__
、 __eq__
、および __ne__
。参照: PEP 207-豊富な比較 。
__cmp__
はnoより長く使用されています。
すなわち、 __lt__
はself
およびother
を引数として取り、self
がother
より小さいかどうかを返す必要があります。例えば:
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):
...
これは、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)
_を使用できます。)
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 = 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