首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么Python没有"__req__“(反射相等)方法?

为什么Python没有"__req__“(反射相等)方法?
EN

Stack Overflow用户
提问于 2017-11-30 23:51:21
回答 3查看 1.1K关注 0票数 7

我有一个小的helper类:

代码语言:javascript
复制
class AnyOf(object):
    def __init__(self, *args):
        self.elements = args
    def __eq__(self, other):
        return other in self.elements

这让我可以像这样做甜蜜的魔术:

代码语言:javascript
复制
>>> arr = np.array([1,2,3,4,5])
>>> arr == AnyOf(2,3)
np.array([False, True, True, False, False])

而不必使用列表理解(就像在np.array(x in (2,3) for x in arr中一样)。

(我维护了一个允许(受信任的)用户输入任意代码的UI,对于不懂技术的用户来说,a == AnyOf(1,2,3)比列表理解要好得多。)

然而!

这只有一种效果!例如,如果我执行AnyOf(2,3) == arr,那么我的AnyOf类的__eq__方法永远不会被调用:相反,将调用NumPy数组的__eq__方法,该方法在内部(我假设)调用其所有元素的__eq__方法。

这让我想知道:为什么Python不允许__eq__的右侧等效项?(大致相当于__radd____rmul__等方法。)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-12-01 00:25:09

在这种语言中,__req__不是一个好主意,因为如果Left类定义了__eq__,而Right类定义了__req__,那么Python就必须一致地决定谁首先在Left() == Right()中被调用。他们不可能都赢。

但是,Python数据模型确实允许您在这里做您想做的事情。您可以从两个方面控制这种比较,但您需要正确定义AnyOf如果希望从右侧控制AnyOf np.ndarray**.**的__eq__,则必须将其定义为的子类

如果我执行AnyOf(2,3) == arr,那么我的AnyOf类的__eq__方法永远不会被调用

不,你在这里有一个根本性的误解。除非右手边是左手边类型的子类,否则左手边总是在相等比较中得到第一次尝试。

代码语言:javascript
复制
arr == AnyOf(2,3)

在上面的例子中,你的自定义__eq__被调用了,因为numpy数组调用了它!所以np.ndarray赢了,它决定对每个元素检查一次。它实际上可以做任何其他事情,包括根本不调用你的AnyOf.__eq__

代码语言:javascript
复制
AnyOf(2,3) == arr

在上面的例子中,您的类进行了第一次比较,但由于使用in (检查数组是否在元组中)的方式而失败。

票数 8
EN

Stack Overflow用户

发布于 2017-12-01 00:07:07

关于像__radd__这样的__rxx__方法的documentation声明:

仅当左操作数不支持相应的操作并且操作数属于不同类型时,才会调用这些函数。

虽然默认情况下类没有__add____sub__方法,但它们do __eq__

代码语言:javascript
复制
>>> class A(object):
...     pass
>>> '__eq__' in dir(A)
True

这意味着__req__永远不会被调用,除非您显式地从另一个类中删除__eq__,或者使__eq__返回NotImplemented

您可以使用np.in1d解决您的特定问题

代码语言:javascript
复制
>>> np.in1d(arr, [2, 3])
array([False,  True,  True, False, False], dtype=bool)
票数 3
EN

Stack Overflow用户

发布于 2017-12-01 00:14:26

这是有关data model的文档

这些方法没有交换参数版本(当左边的参数不支持操作,而右边的参数支持时使用);相反,__lt__()__gt__()是彼此的反射,__le__()__ge__()是对方的反射,__eq__()__ne__()是它们自己的反射。如果两个操作数的类型不同,且右操作数的类型是左操作数类型的直接或间接子类,则右操作数的反射方法优先,否则左操作数的方法优先。不考虑虚拟子类化。

正如上面的注释所述,您想要的东西是有效的,__eq__本质上与潜在的__req__相同:如果左侧的对象返回NotImplemented,则在==的右侧调用它

代码语言:javascript
复制
In [1]: class A:
   ...:     def __eq__(self, other):
   ...:         return NotImplemented
   ...:     

In [2]: class B:
   ...:     def __eq__(self, other): 
   ...:         print("B comparing")
   ...:         return True
   ...:     

In [3]: B() == A()
B comparing
Out[3]: True

In [4]: A() == B()
B comparing
Out[4]: True

In [5]: A() == A()
Out[5]: False

当它出现时,它甚至可以与其他普通对象一起工作:

代码语言:javascript
复制
In [10]: 5 == B()
B comparing
Out[10]: True

然而,一些对象可能会在__eq__上产生TypeError,而不是返回NotImplementedFalse,这使得这对所有类型的对象都不可靠。

在您的例子中,是在您自己的__eq__方法中不正确地使用了运算符in和数组和元组。(感谢@wim在这里的另一个答案中发现了这一点)。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47577395

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档