【发布时间】:2021-12-09 07:55:42
【问题描述】:
一个略长的问题,足以解释背景......
假设有一个内置的class A:
class A:
def __init__(self, a=None):
self.a = a
def __eq__(self, other):
return self.a == other.a
预计这样比较:
a1, a2 = A(1), A(2)
a1 == a2 # False
出于某种原因,团队在其之上引入了一个包装器(代码示例实际上并未包装 A 以简化代码复杂性。)
class WrapperA:
def __init__(self, a=None):
self.pa = a
def __eq__(self, other):
return self.pa == other.pa
同样,它应该以这种方式进行比较:
wa1, wa2 = WrapperA(1), WrapperA(2)
wa1 == wa2 # False
虽然预计会使用A 或WrapperA,但问题是某些代码库包含这两种用法,因此以下比较失败:
a, wa = A(), WrapperA()
wa == a # AttributeError
a == wa # AttributeError
一个已知的解决方案是修改__eq__:
对于wa == a:
class WrapperA:
def __init__(self, a=None):
self.pa = a
def __eq__(self, other):
if isinstance(other, A):
return self.pa == other.a
return self.pa == other.pa
对于a == wa:
class A:
def __init__(self, a=None):
self.a = a
def __eq__(self, other):
if isinstance(other, WrapperA):
return self.a == other.pa
return self.a == other.a
需要修改 WrapperA。对于A,既然是内置的东西,有两种解决方案:
- 使用 setattr 扩展 A 以支持 WrapperA。
setattr(A, '__eq__', eq_that_supports_WrapperA)
- 强制开发者只比较
wa == a(然后不关心a == wa)。
第一个选项对于重复实现显然很难看,第二个给开发人员带来了不必要的“惊喜”。所以我的问题是,是否有一种优雅的方法可以通过内部 Python 实现将 a == wa 的任何用法替换为 wa == a?
【问题讨论】:
-
请注意,
==通常适用于 所有 类型。A.__eq__要求other成为A实际上是一个应该修复的错误。当它无法做出决定时,它至少应该返回NotImplemented。 -
“内置事物”是指builtin type(或标准库中的其他类型)还是第三方库类型?
-
无论你最终做什么,我建议你对
A和WrapperA进行大量测试,这样当有一天有人介绍WrapperWrapperA和BaseA时,你知道一切仍然有效. -
@MisterMiyagi 例如ipaddress。假设我们要制作一个包装器(例如:
IPAddress)并使其与ipaddress.IPv4Address和ipaddress.IPv6Address具有可比性。 -
在那种情况下我很困惑——
ipaddress类似乎在other不兼容时正确返回NotImplemented。这意味着修改“WrapperA”就足够了。