__eq__ 引发异常的陷阱?
Pitfalls to having __eq__ raise an exception?
我有一种类型,其中相等比较没有意义。显式比较此类型的两个实例的引用或值相等将指示调用代码中的逻辑错误。
定义__eq__
引发异常不好吗?这有什么陷阱吗?它是否作为某些常见操作的一部分被隐式调用?
在像 Haskell 这样的语言中,我根本不会实现 Equal 类型类,并且尝试进行比较将是一个编译错误。由于 python 是完全动态的,如果这个定义不是一个好主意,我是否有一个选项可以帮助鼓励正确使用?
我可以 return NotImplemented
,但如果 RHS 也 returns NotImplemented
,它会进行后备比较,最终会导致身份比较,但我仍然不希望那样.
使 __eq__
throw 将阻止您的 class 被用作字典中的键。字典是 "attach" 将任意值引用到可比较对象的常用方法。
例如:
class NotComparableAtAll:
def __eq__(self, other):
raise ValueError ('haha')
cache = { }
x, y = NotComparableAtAll (), NotComparableAtAll ()
cache[x] = 1
cache[y] = 2
这失败了,说该类型不可散列。
但是,如果您将 __hash__
添加到 class(一旦您定义 __eq__
,默认值就会被删除),示例 出现 几乎所有时间都可以正常工作,只有当两个不同的对象在某台机器上具有相同的哈希时,它才会不可预测地失败。要重现它,请将 __hash__
定义为始终 return 0(这确实符合 __hash__
要求)。
此外,像这样重写 __eq__
会破坏一些标准函数,在这些函数中,通过引用进行比较很有用:
my_list = [x, y]
my_list.remove (y)
这当然可以被视为 "these objects must really not be compared" 的另一种情况,但我想人们可以想出其他类似的例子,其中比较以某种方式嵌套在不同的有用操作中。
我有一种类型,其中相等比较没有意义。显式比较此类型的两个实例的引用或值相等将指示调用代码中的逻辑错误。
定义__eq__
引发异常不好吗?这有什么陷阱吗?它是否作为某些常见操作的一部分被隐式调用?
在像 Haskell 这样的语言中,我根本不会实现 Equal 类型类,并且尝试进行比较将是一个编译错误。由于 python 是完全动态的,如果这个定义不是一个好主意,我是否有一个选项可以帮助鼓励正确使用?
我可以 return NotImplemented
,但如果 RHS 也 returns NotImplemented
,它会进行后备比较,最终会导致身份比较,但我仍然不希望那样.
使 __eq__
throw 将阻止您的 class 被用作字典中的键。字典是 "attach" 将任意值引用到可比较对象的常用方法。
例如:
class NotComparableAtAll:
def __eq__(self, other):
raise ValueError ('haha')
cache = { }
x, y = NotComparableAtAll (), NotComparableAtAll ()
cache[x] = 1
cache[y] = 2
这失败了,说该类型不可散列。
但是,如果您将 __hash__
添加到 class(一旦您定义 __eq__
,默认值就会被删除),示例 出现 几乎所有时间都可以正常工作,只有当两个不同的对象在某台机器上具有相同的哈希时,它才会不可预测地失败。要重现它,请将 __hash__
定义为始终 return 0(这确实符合 __hash__
要求)。
此外,像这样重写 __eq__
会破坏一些标准函数,在这些函数中,通过引用进行比较很有用:
my_list = [x, y]
my_list.remove (y)
这当然可以被视为 "these objects must really not be compared" 的另一种情况,但我想人们可以想出其他类似的例子,其中比较以某种方式嵌套在不同的有用操作中。