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