Python允许像x > y > z
这样的表达式,根据文档,它等同于(x > y) and (y > z)
,除了y
只评估一次。 (https://docs.python.org/3/reference/expressions.html)
但是,如果我自定义比较功能,这似乎会中断。例如。假设我有以下类:(对于大块的道歉,但是一旦你阅读__eq__
方法,其余的都是微不足道的。)
class CompareList(list):
def __repr__(self):
return "CompareList([" + ",".join(str(x) for x in self) + "])"
def __eq__(self, other):
if isinstance(other, list):
return CompareList(self[idx] == other[idx] for idx in xrange(len(self)))
else:
return CompareList(x == other for x in self)
def __ne__(self, other):
if isinstance(other, list):
return CompareList(self[idx] != other[idx] for idx in xrange(len(self)))
else:
return CompareList(x != other for x in self)
def __gt__(self, other):
if isinstance(other, list):
return CompareList(self[idx] > other[idx] for idx in xrange(len(self)))
else:
return CompareList(x > other for x in self)
def __ge__(self, other):
if isinstance(other, list):
return CompareList(self[idx] >= other[idx] for idx in xrange(len(self)))
else:
return CompareList(x >= other for x in self)
def __lt__(self, other):
if isinstance(other, list):
return CompareList(self[idx] < other[idx] for idx in xrange(len(self)))
else:
return CompareList(x < other for x in self)
def __le__(self, other):
if isinstance(other, list):
return CompareList(self[idx] <= other[idx] for idx in xrange(len(self)))
else:
return CompareList(x <= other for x in self)
现在我可以做一些有趣的事情,比如CompareList([10, 5]) > CompareList([5, 10])
,它会正确返回CompareList([True,False])
然而,链接这些操作并不能很好地运作:
low = CompareList([1])
high = CompareList([2])
print(low > high > low) # returns CompareList([True])
为什么不呢?引擎盖下发生了什么?我知道它不等于(low > high) > low
= (False > low)
(因为那将返回False)。它可能是low > (high > low)
,但就运算符优先级(通常是从左到右)而言没有意义。
答案 0 :(得分:8)
Python允许像
x > y > z
这样的表达式,根据文档,这些表达式等同于(x > y) and (y > z)
,除了y
只评估一次。
根据这一点,low > high > low
将等同于(low > high) and (high > low)
。
>>> x = low > high # CompareList([False])
>>> y = high > low # CompareList([True])
>>> x and y
CompareList([True])
有关x and y的文档中的更多内容:
x and y
:如果x
为假,则为x
,否则为y
在上述情况中:
>>> x is False
False
>>> x if x is False else y # x and y
CompareList([True])
所以当你x and y
时,它会返回y
CompareList([True])
。
答案 1 :(得分:3)
其他答案是正确的,但我想解决这个问题的实际缺乏实现,因为,正如我所相信的那样,OP希望从{{1是low > high > low
。
确实,CompareList([False])
评估为low > high > low
,而(low > high) and (high > low)
评估为CompareList([False]) is False
(这意味着它是False
),那么第二个操作数True
运算符被评估并返回(因为它也计算为and
)。
实现链式比较的关键是覆盖True
和and
上的__gt__
布尔运算符。
不幸的是,没有办法做到这一点,而且可能不会成功。 PEP 335 - Overloadable Boolean Operators
proposal被Guido拒绝,但他可能会考虑将链式比较作为&lt; b&lt; c overable [1]。
除非那一刻,否则在使用链式比较时无法使您的示例按预期工作。
实现正确结果的唯一方法是重写__lt__
方法并编写如下比较:
__and__
然后,通过下面的表格,您将得到正确答案:
def CompareList(list):
...
def __and__(self, other):
if isinstance(other, list):
return CompareList(self[idx] and other[idx] for idx in range(len(self)))
else:
return CompareList(x and other for x in self)
答案 2 :(得分:1)
您应该从比较方法中返回一个布尔值。
引用documentation for "rich comparison" methods:
按照惯例,成功返回False和True 比较。但是,这些方法可以返回任何值,所以如果 比较运算符用于布尔上下文中(例如,在 if语句的条件),Python会将值调用bool() 确定结果是真还是假。
为了解决这个问题:
exp1 = low > high
print(exp1)
print(bool(exp1))
exp2 = high > low
print(exp2)
print(bool(exp2))
会给你
CompareList([False])
True
CompareList([True])
True
现在我们进行最后一次操作并打印出结果
print(exp1 and exp2)
因为这两个值都会计算为True
,所以
CompareList([True])