非常好奇。
我注意到(至少在py 2.6和2.7中)float
拥有所有熟悉的丰富比较函数:__lt__()
,__gt__
,__eq__
等等。
>>> (5.0).__gt__(4.5)
True
但int
不
>>> (5).__gt__(4)
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'int' object has no attribute '__gt__'
这对我来说很奇怪,因为运营商本身工作正常
>>> 5 > 4
True
偶数字符串支持比较功能
>>> "hat".__gt__("ace")
True
但所有int
都有__cmp__()
对我来说似乎很奇怪,所以我想知道为什么会这样。
刚刚测试过,它在python 3中按预期工作,所以我假设有一些遗留原因。仍然希望听到正确的解释;)
答案 0 :(得分:21)
如果我们查看PEP 207 for Rich Comparisions,最后会有一个有趣的句子:
处理整数比较的内联已经存在仍然适用,导致最常见情况没有性能成本。
所以似乎在2.x中存在整数比较的优化。如果我们take a look at the source code,我们可以找到:
case COMPARE_OP:
w = POP();
v = TOP();
if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) {
/* INLINE: cmp(int, int) */
register long a, b;
register int res;
a = PyInt_AS_LONG(v);
b = PyInt_AS_LONG(w);
switch (oparg) {
case PyCmp_LT: res = a < b; break;
case PyCmp_LE: res = a <= b; break;
case PyCmp_EQ: res = a == b; break;
case PyCmp_NE: res = a != b; break;
case PyCmp_GT: res = a > b; break;
case PyCmp_GE: res = a >= b; break;
case PyCmp_IS: res = v == w; break;
case PyCmp_IS_NOT: res = v != w; break;
default: goto slow_compare;
}
x = res ? Py_True : Py_False;
Py_INCREF(x);
}
else {
slow_compare:
x = cmp_outcome(oparg, v, w);
}
所以似乎在2.x中存在一个现有的性能优化 - 通过允许C代码直接比较整数 - 如果已经实现了丰富的比较运算符,则不会保留这些整数。
现在在Python 3中不再支持__cmp__
,因此必须有丰富的比较运算符。据我所知,现在这不会导致性能下降。例如,比较:
Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.timeit("2 < 1")
0.06980299949645996
为:
Python 3.2.3 (v3.2.3:3d0686d90f55, Apr 10 2012, 11:25:50)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.timeit("2 < 1")
0.06682920455932617
所以似乎有类似的优化,但我的猜测是判断调用是将它们全部放在2.x分支中,当向后兼容性是一个考虑时,这将是一个太大的变化。
在2.x中如果你想要丰富的比较方法,你可以通过operator
module得到它们:
>>> import operator
>>> operator.gt(2,1)
True
答案 1 :(得分:5)
__cmp__()
是一种老式的比较方式,deprecated in favor of the rich operators(__lt__
,__le__
等)仅在Python 2.1中引入。可能从2.7.x开始,转换不完整 - 而在Python 3.x __cmp__
中完全删除了。
Haskell拥有我见过的最优雅的实现 - 成为Ord
(序数)数据类型,您只需要定义<
和=
的工作方式,以及类型本身为<=
,>
和>=
提供了这两者的默认实现(如果你愿意,你可以自己定义自己)。您可以在Python中自己编写这样的类,不确定为什么不是默认类;可能是表现原因。
答案 2 :(得分:1)
正如hircus所说,Python中的__cmp__
样式比较是deprecated in favor of the rich operators(__lt__
,...)。最初,比较是使用__cmp__
实现的,但也有一些简单__cmp__
运算符不足的类型/情况(例如,Color类的实例可以支持==
和!=
,但不支持<
或>
),因此添加了丰富的比较运算符,留下__cmp__
以便向后兼容。遵循python哲学“应该有一个 - 最好只有一个 - 显而易见的方式”, 1 在Python 3中删除了遗留支持,这样可以牺牲向后兼容性。 / p>
在Python 2中,尽管int
仍然使用__cmp__
以便不破坏向后兼容性,但并非所有浮点数都小于,大于或等于其他浮点数(例如{ {1}}评估为(float('nan') < 0.0, float('nan') == 0.0, float('nan') > 0.0)
,那么(False, False, False)
应返回什么?),因此float('nan').__cmp__(0.0)
需要使用较新的丰富比较运算符。
1 :尝试在python shell中输入“import this”。