为什么Python没有“__req__”(反映相等)方法?

时间:2017-11-30 15:51:21

标签: python numpy python-internals python-datamodel

我有一个小助手班:

class AnyOf(object):
    def __init__(self, *args):
        self.elements = args
    def __eq__(self, other):
        return other in self.elements

这让我可以做出如下的甜蜜魔法:

>>> 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)。

(我维护一个让(可信)用户输入任意代码的用户界面,a == AnyOf(1,2,3)比非技术精明用户的列表理解更可口。)

然而!

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

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

3 个答案:

答案 0 :(得分:5)

import os os.system('CLS') user_input = '' while user_input != 'quit': user_input = input('Input something:') os.system('CLS') # Clear the console. # On Unix systems you have to use 'clear' instead of 'CLS'. # os.system('clear') 在该语言中不是一个好主意,因为如果类__req__定义Left而类__eq__定义Right,那么Python就有义务在__req__中做出关于谁首先被召唤的一致决定。他们无法获胜。

但是,Python数据模型确实允许您在此处执行所需操作。从两侧您可以控制此比较,但您需要正确定义Left() == Right()如果您希望AnyOf从右侧控制__eq__,则必须将其定义为AnyOf的子类。

  

如果我要np.ndarray,那么我的AnyOf(2,3) == arr课程AnyOf方法永远不会被调用

不,你在这里有一个根本的误解。除非右侧是左侧类型的子类,否则左侧总是首先尝试相等比较。

__eq__

在上面的情况中,您的自定义arr == AnyOf(2,3) 调用,因为numpy数组会调用它!所以__eq__获胜,并决定每个元素检查一次。它确实可以做任何其他事情,包括根本不打电话给你np.ndarray

AnyOf.__eq__

在上面的例子中,你的类确实在比较时首次尝试,并且由于你使用AnyOf(2,3) == arr 的方式(检查数组是否在元组中)而失败。

答案 1 :(得分:2)

关于__radd__方法的documentation __add__州:

  

仅当左操作数不支持时才调用这些函数   相应的操作和操作数是不同类型的。

虽然每个默认类没有__sub____eq__方法,但执行>>> class A(object): ... pass >>> '__eq__' in dir(A) True

__req__

这意味着永远不会调用__eq__,除非您从其他类中明确删除np.in1d

您可以使用>>> np.in1d(arr, [2, 3]) array([False, True, True, False, False], dtype=bool) 解决您的具体问题:

{{1}}

答案 2 :(得分:1)

这是data model上的文档:

  

这些方法没有交换参数版本(当左参数不支持操作但是支持时使用   正确的论据确实);相反,__lt__()__gt__()是彼此的   反射,__le__()__ge__()是彼此的反映,和    __eq__() __ne__()是他们自己的反映。如果操作数是不同类型的,则右操作数的类型是直接或间接的   左操作数类型的子类,右侧的反射方法   操作数有优先级,否则左操作数的方法有   优先。不考虑虚拟子类化。

如上面的评论中所述,您想要的是什么,__eq__与潜在的__req__基本相同:如果==NotImplemented的右侧调用它左侧的对象返回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

In [10]: 5 == B()
B comparing
Out[10]: True

实际上,它甚至可以与其他普通对象一起使用:

__eq__

但是,某些对象可能会在NotImplemented上产生TypeError,而不是返回Falsein,这使得这对所有类型的对象都不可靠。

在您的情况下发生的情况是,在您自己的__eq__方法中使用数组和元组的运算符<div id="fullpage"> <div class="section">One</div> <div class="section">Two</div> <div id="three" class="section">Three</div> <div id="four" class="section fp-normal-height fp-normal-scroll"> <div style="height:1000px;">Four</div> </div> </div> <footer style="height:300px;">Site footer</footer> $('#fullpage').fullpage({ sectionsColor: ['yellow', 'orange', '#C0C0C0', '#ADD8E6'], hybrid:true, fitToSection: false, afterLoad: function(anchorLink, index){ var loadedSection = $(this); if(loadedSection.attr("id") == "four") { $.fn.fullpage.setAutoScrolling(false); } if(loadedSection.attr("id") == "three") { $.fn.fullpage.setAutoScrolling(true); } }, }); 是错误的。 (感谢@wim在这里的另一个答案中发现了这一点。)