要使自定义 class 的对象具有可比性,仅定义 `__eq__` 和 `__lt__` 家族中的几个成员就足够了吗?
To make objects of a custom class comparable, is it enough to define just a few of the members in `__eq__` and `__lt__` family?
假设我有一个 class,我想将其中的成员与常用运算符 ==
、<
、<=
、>
进行比较, 和 >=
.
据我所知,这可以通过初始化定义魔术方法 __cmp__(a, b)
来实现,其中 returns -1 (a < b
)、0 (a == b
) 或 1 (a > b
).
似乎__cmp__
was deprecated since Python 3 支持定义__eq__
、__lt__
、__le__
、__gt__
和_ge__
方法分开。
我定义了 __eq__
和 __lt__
,假设 __le__
的默认值类似于 return a == b or a < b
。下面的class似乎不是这样:
class PQItem:
def __init__(self, priority, item):
self.priority = priority
self.item = item
def __eq__(self, other):
return isinstance(other, PQItem) and self.priority == other.priority
def __lt__(self, other):
return isinstance(other, PQItem) and self.priority < other.priority
class NotComparable:
pass
x = NotComparable()
y = NotComparable()
# x < y gives error
我得到了这个结果:
>>> PQItem(1, x) == PQItem(1, y)
True
>>> PQItem(1, x) < PQItem(1, y)
False
>>> PQItem(1, x) <= PQItem(1, y)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: PQItem() <= PQItem()
这让我得出结论,我必须手动定义所有比较魔术方法才能使 class 具有可比性。有没有更好的方法?
为什么 __cmp__
被弃用了?这似乎是一种更好的处理方式
对于两个对象a
和b
,__cmp__
需要a < b
、a == b
之一,并且 a > b
为真。但情况可能并非如此:考虑集合,其中 none of those 为真是很常见的,例如{1, 2, 3}
对比 {4, 5, 6}
.
于是__lt__
之类的东西被引入。但这让 Python 有两个独立的排序机制,这有点荒谬,所以在 Python 3.
中删除了不太灵活的机制。
您实际上不必实现所有六种比较方法。您可以使用 functools.total_ordering
class 装饰器来帮助定义其余的魔术比较方法:
from functools import total_ordering
@total_ordering
class PQItem:
def __init__(self, priority, item):
self.priority = priority
self.item = item
def __eq__(self, other):
return isinstance(other, PQItem) and self.priority == other.priority
def __lt__(self, other):
return isinstance(other, PQItem) and self.priority < other.priority
假设我有一个 class,我想将其中的成员与常用运算符 ==
、<
、<=
、>
进行比较, 和 >=
.
据我所知,这可以通过初始化定义魔术方法 __cmp__(a, b)
来实现,其中 returns -1 (a < b
)、0 (a == b
) 或 1 (a > b
).
似乎__cmp__
was deprecated since Python 3 支持定义__eq__
、__lt__
、__le__
、__gt__
和_ge__
方法分开。
我定义了 __eq__
和 __lt__
,假设 __le__
的默认值类似于 return a == b or a < b
。下面的class似乎不是这样:
class PQItem:
def __init__(self, priority, item):
self.priority = priority
self.item = item
def __eq__(self, other):
return isinstance(other, PQItem) and self.priority == other.priority
def __lt__(self, other):
return isinstance(other, PQItem) and self.priority < other.priority
class NotComparable:
pass
x = NotComparable()
y = NotComparable()
# x < y gives error
我得到了这个结果:
>>> PQItem(1, x) == PQItem(1, y)
True
>>> PQItem(1, x) < PQItem(1, y)
False
>>> PQItem(1, x) <= PQItem(1, y)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: PQItem() <= PQItem()
这让我得出结论,我必须手动定义所有比较魔术方法才能使 class 具有可比性。有没有更好的方法?
为什么 __cmp__
被弃用了?这似乎是一种更好的处理方式
对于两个对象a
和b
,__cmp__
需要a < b
、a == b
之一,并且 a > b
为真。但情况可能并非如此:考虑集合,其中 none of those 为真是很常见的,例如{1, 2, 3}
对比 {4, 5, 6}
.
于是__lt__
之类的东西被引入。但这让 Python 有两个独立的排序机制,这有点荒谬,所以在 Python 3.
您实际上不必实现所有六种比较方法。您可以使用 functools.total_ordering
class 装饰器来帮助定义其余的魔术比较方法:
from functools import total_ordering
@total_ordering
class PQItem:
def __init__(self, priority, item):
self.priority = priority
self.item = item
def __eq__(self, other):
return isinstance(other, PQItem) and self.priority == other.priority
def __lt__(self, other):
return isinstance(other, PQItem) and self.priority < other.priority