Python中的过度隐藏比较方法

Python中的过度隐藏比较方法,python,python-3.x,Python,Python 3.x,我从我的一个朋友那里遇到了这个代码。这是一个在Python中对比较方法进行过度隐藏的测试。当我运行代码时,我得到了以下信息: 真的 真的 真的 这是:“TypeError:”你也需要在classA中定义\uu lt\uu: A类: 定义初始化(self,x): self.x=x 定义(自身、其他): 返回self.x

我从我的一个朋友那里遇到了这个代码。这是一个在Python中对比较方法进行过度隐藏的测试。当我运行代码时,我得到了以下信息:

真的

真的

真的


这是:“TypeError:”你也需要在class
A
中定义
\uu lt\uu

A类:
定义初始化(self,x):
self.x=x
定义(自身、其他):
返回self.x
当然,对于其他操作符也是如此。之所以会发生这种情况,是因为在
b
中,调用的方法是
b.\uu lt\uu
而在
a
中,调用的方法是
a.\uu lt\uu
。定义了前一种方法,但没有定义后一种方法


顺便说一句,您在
B
的构造函数中调用了
A
的构造函数。我假设您希望A
B
也是
A
,因此
B
继承自
A
。这就是我的代码显示
B(A)类的原因

因此我更改了您的代码,将
print
语句添加到
\uuuu eq\uuu
方法中,如下所示:

class A:
    def __init__(self, x):
        self.x = x
class B:
    def __init__(self, x):
        A.__init__(self, x)
    def __eq__(self, other):
        print('type(self) =', type(self))
        print('type(other) =', type(other))
        return self.x == other.x
    def __lt__(self, other):
        return self.x < other.x
A类:
定义初始化(self,x):
self.x=x
B类:
定义初始化(self,x):
A.uuu初始(self,x)
定义(自身、其他):
打印('type(self)=',type(self))
打印('类型(其他)=',类型(其他))
返回self.x==other.x
定义(自身、其他):
返回self.x
结果是:

type(self) = <class '__main__.B'>
type(other) = <class '__main__.A'>
True
type(self) = <class '__main__.B'>
type(other) = <class '__main__.A'>
True
True
Traceback (most recent call last):
  File "/home/chrx/Dropbox/Documents/Programming/questions/SO_question.py", line 25, in <module>
    print(a3 < b3)
TypeError: unorderable types: A() < B()
类型(自身)=
类型(其他)=
真的
类型(自身)=
类型(其他)=
真的
真的
回溯(最近一次呼叫最后一次):
文件“/home/chrx/Dropbox/Documents/Programming/questions/SO_question.py”,第25行,在
打印(a3
因此,即使您只为
B
类编写了一个
\uuuuu eq\uuu
方法,但在以相反顺序进行比较时使用了该方法,
a==B
。这(我相信)是Python语言的一个特性,它假设等式运算符是自反的,即
a==B
B==a
应该具有相同的结果


但是,在这种情况下,此属性不适用于
\uu lt\uuu
运算符,因为
a
不同于
b
如果
a
在正常情况下比较没有意义,
b
可以完成所有比较的繁重工作在
A
B
之间,但您需要实现反映的比较运算符才能工作

这里的问题是
A
没有实现
\uuu lt\uuu
,因此Python将使用
B
中的反射操作符执行
a3
,进行行测试
b3>a3
。但是您没有在
B
中实现
\uu gt\uucode>,因此无法反映操作

最简单的修复方法(如果您实现了任何比较操作,通常建议您这样做)是将单个实现的运算符扩展到整个富比较套件:

from functools import total_ordering

@total_ordering
class B:
     ... rest of B unchanged ...
就是这样;您的代码将正常工作,因为这种装饰将确保
\uuuugt\uuuu
是根据
\uult\uuu
/
\uuuuueq\uuu
定义的,因此翻转比较的尝试将成功

您可以逐个等效地定义每个操作,例如:

class B:
    ... rest of class ...
    def __gt__(self, other):
        return self.x > other.x
    def __le__(self, other):
        return self.x <= other.x
    def __ge__(self, other):
        return self.x >= other.x
B类:
……其他同学。。。
定义(自身、其他):
返回self.x>other.x
定义(自我、其他):
返回self.x=其他.x
但这很繁琐且容易出错;请使用
functools.total\u ordering


=
测试工作得很好,因为等式是自反的,所以当另一个操作数没有实现它时,相同的重载在两个方向上都起作用;Python尝试
a.。\uuuuueq\uuuuuu(b)
发现它不起作用,所以它尝试
b.\uuuueq\uuuuu(a)
,因为
a==b
在逻辑上等同于
b==a
。只有在反射的操作使用不同方法的情况下,才能进行丰富的比较。

还请评论类b
类b(a)中从类a继承的内容:
OP在他/她的代码中忘记了这一点。如果B从A继承?@Bazingaa,是否真的有必要实现两次
\uu lt\uuuu
。继承在这里是不必要的。调用
A。
B中的
。\uuuuuu init\uuuuuuu
可能看起来很奇怪,但在任何方面都不是非法的。@凯文de>B
如果它在超类中正确实现。在
B中调用
A.\uuuu init\uuuu
。\uu init\uuuu
可能不是非法的,但这是一种模式,您永远不应该使用此属性应用于
\uu lt\uuuu
,只是它会翻转以遵循逻辑;如果
A.\uu lt\uuu(B)
A
)未实现,Python尝试
b.\uuu gt\uuuuuuuuuuuuuuuua
b>a
)。涵盖了在不修改
a
的情况下正确修复此问题。您是否忘记说
b类(a)
,因此
b
的实例也是
a
的实例?
class B:
    ... rest of class ...
    def __gt__(self, other):
        return self.x > other.x
    def __le__(self, other):
        return self.x <= other.x
    def __ge__(self, other):
        return self.x >= other.x