Python:为什么int类没有像`__lt __()`那样丰富的比较运算符?

jis*_*one 21 python language-design language-history

非常好奇.

我已经注意到了(至少在PY 2.6和2.7),一个float拥有所有熟悉的丰富的比较函数:__lt__(),__gt__,__eq__等.

>>> (5.0).__gt__(4.5)
True
Run Code Online (Sandbox Code Playgroud)

但是int没有

>>> (5).__gt__(4)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'int' object has no attribute '__gt__'
Run Code Online (Sandbox Code Playgroud)

这对我来说很奇怪,因为运营商本身运作良好

>>> 5 > 4
True
Run Code Online (Sandbox Code Playgroud)

甚至字符串也支持比较功能

>>> "hat".__gt__("ace")
True
Run Code Online (Sandbox Code Playgroud)

但所有的int都是__cmp__()

对我来说似乎很奇怪,所以我想知道为什么会这样.

刚刚测试过,它在python 3中按预期工作,所以我假设有一些遗留原因.仍然希望听到正确的解释;)

Dav*_*ebb 21

如果我们查看PEP 207 for Rich Comparisions,最后会有一个有趣的句子:

处理整数比较的内联已经存在仍然适用,导致最常见情况没有性能成本.

因此,似乎在2.x中存在整数比较的优化.如果我们看一下源代码,我们可以找到:

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);
    }
Run Code Online (Sandbox Code Playgroud)

因此,似乎在2.x中存在一个现有的性能优化 - 通过允许C代码直接比较整数 - 如果已经实现了丰富的比较运算符,则不会保留这些整数.

现在__cmp__不再支持Python 3,因此必须有丰富的比较运算符.据我所知,现在这不会导致性能下降.例如,比较:

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
Run Code Online (Sandbox Code Playgroud)

至:

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
Run Code Online (Sandbox Code Playgroud)

所以似乎有类似的优化,但我的猜测是判断调用是将它们全部放在2.x分支中,当向后兼容性是一个考虑时,这将是一个太大的变化.

在2.x中如果你想要丰富的比较方法,你可以通过operator模块得到它们:

>>> import operator
>>> operator.gt(2,1)
True
Run Code Online (Sandbox Code Playgroud)


mic*_*slm 5

__cmp__()是做的比较老式的方式,并支持丰富的运营商弃用(__lt__,__le__其中只在Python 2.1引入等).可能从2.7.x开始过渡并不完整 - 而在Python 3.x __cmp__中完全删除了.

Haskell拥有我见过的最优雅的实现 - 成为Ord(序数)数据类型,你只需要定义如何<=工作,类型类本身提供默认实现<=,>并且>=就这两者而言(你是如果你愿意,欢迎定义自己).您可以在Python中自己编写这样的类,但不确定为什么不是默认类; 可能性能原因.