acd*_*cdr 6 python numpy python-datamodel python-internals
我有一个小助手班:
class AnyOf(object):
def __init__(self, *args):
self.elements = args
def __eq__(self, other):
return other in self.elements
Run Code Online (Sandbox Code Playgroud)
这让我做了甜蜜的魔术:
>>> arr = np.array([1,2,3,4,5])
>>> arr == AnyOf(2,3)
np.array([False, True, True, False, False])
Run Code Online (Sandbox Code Playgroud)
无需使用列表理解(如np.array(x in (2,3) for x in arr).
(我维护一个让(可信)用户输入任意代码的用户界面,并且a == AnyOf(1,2,3)比非技术精明用户的列表理解更加可口.)
然而!
这只适用于一种方式!例如,如果我这样做,AnyOf(2,3) == arr那么我的AnyOf类的__eq__方法永远不会被调用:相反,NumPy数组的__eq__方法被调用,在内部(我会假设)调用其__eq__所有元素的方法.
这让我想知道:为什么Python不允许右侧等效__eq__?(大致相当于像__radd__,__rmul__等等的方法.)
一个__req__是不是在语言是一个好主意,因为如果类Left定义__eq__和类Right定义__req__,那么Python有义务作出关于谁最先被叫做一致的决定Left() == Right().他们不可能双赢.
但是,Python数据模型确实允许您在此处执行所需操作.从两侧您可以控制此比较,但您需要AnyOf正确定义. 如果AnyOf要从右侧控制__eq__,则必须将其定义为的子类np.ndarray.
如果我这样做,
AnyOf(2,3) == arr那么我的AnyOf班级__eq__方法永远不会被调用
不,你在这里有一个根本的误解.除非右侧是左侧类型的子类,否则左侧总是首先尝试相等比较.
arr == AnyOf(2,3)
Run Code Online (Sandbox Code Playgroud)
在上述情况下,您的自定义__eq__ 时被调用,因为numpy的数组调用它!所以np.ndarray赢了,并决定每个元素检查一次.它确实可以做任何其他事情,包括根本不打电话给你AnyOf.__eq__.
AnyOf(2,3) == arr
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,你的类确实在比较时首次尝试,并且由于你使用的方式in(检查数组是否在元组中)而失败.
这是有关数据模型的文档:
\n\n\n\n\n这些方法没有交换参数版本(当左参数不支持该操作但右参数支持时使用);相反,
\n__lt__()和__gt__()是彼此\xe2\x80\x99s\n 的反射,__le__()和__ge__()是彼此\xe2\x80\x99s 的反射,并且\n__eq__()和__ne__()是它们自己的反射。如果操作数的类型不同,并且右操作数\xe2\x80\x99s类型是左操作数\xe2\x80\x99s类型的直接或间接子类,则右操作数的反射方法具有优先级,否则左操作数\xe2\x80\x99s 方法具有优先级。不考虑虚拟子类化。
正如上面的评论中所述,您想要的有效,并且__eq__本质上与潜在的相同:如果左侧的对象返回,则在右侧__req__调用它:==NotImplemented
In [1]: class A:\n ...: def __eq__(self, other):\n ...: return NotImplemented\n ...: \n\nIn [2]: class B:\n ...: def __eq__(self, other): \n ...: print("B comparing")\n ...: return True\n ...: \n\nIn [3]: B() == A()\nB comparing\nOut[3]: True\n\nIn [4]: A() == B()\nB comparing\nOut[4]: True\n\nIn [5]: A() == A()\nOut[5]: False\nRun Code Online (Sandbox Code Playgroud)\n\n它甚至可以与其他普通对象一起使用:
\n\nIn [10]: 5 == B()\nB comparing\nOut[10]: True\nRun Code Online (Sandbox Code Playgroud)\n\n但是,某些对象可能会产生 TypeError on__eq__而不是返回NotImplementedor False,这使得这对于所有类型的对象都不可靠。
在您的情况下发生的情况是in 在您自己的__eq__方法中错误地使用了带有数组和元组的运算符。(感谢@wim 在另一个答案中发现了这一点)。