Python 中的一个奇怪现象

Posted

技术标签:

【中文标题】Python 中的一个奇怪现象【英文标题】:A curious occurrence in Python 【发布时间】:2011-12-20 14:30:57 【问题描述】:

由于某种原因,tuple > list 形式的 Python 2.7 表达式返回 True,但 tuple < listtuple == list 返回 False。这是为什么呢?

这个观察无论如何都不是我的原创。

【问题讨论】:

见Why is ''>0 True in Python?和Why does 4 < '3' return True in Python 2? 【参考方案1】:

tuplelist 不是同一类型。当比较不同类型的值并且没有定义跨这些类型工作的比较器时,Python 做了一些令人惊讶的事情。它比较类名称的字典顺序

>>> class Coffee(object):
...     pass
... 
>>> class Tea(object):
...     pass
... 
>>> c = Coffee()
>>> t = Tea()
>>> c > t
False
>>> c == t
False
>>> c < t
True
>>> 

谢天谢地,在 python 3 中,这种情况消失了,比较这些类型会引发异常。

【讨论】:

"tuplelist 不是同一类型。"错了,它们都是type类型。 @Sven Marnach: 可能我的语法不是很清楚,listtuple 这两种类型 相同的类型,type(list) is type(tuple) 但它们不是同一类型,type(list) is type and type(tuple) is type and list is not tuple tuplelist 显然是不同的类型,但这对于这个问题完全无关紧要。 OP 询问了 list &lt; tuple 等的奇怪结果,但您的回答一直在谈论比较不同类型的值,即使在示例代码中也是如此。这绝对不是你的语法不清楚的问题——我的意思是这个答案没有抓住重点(尽管只是稍微)。您解释了不同类型的值按其类型名称的字典顺序排序——这与比较 listtuple 有什么关系? 我们对问题的解释不同;我理解 Alexei 的“forms of the form tuple > list”(强调我的)'list' 和 'tuple' 词是元句法变量,代表那些类型的值,而不是键入内置listtuple 的值。 你是对的——我没有想到你阅读问题的方式。这是有道理的,感谢您的澄清【参考方案2】:

来自the doc:

运算符&lt;&gt;==&gt;=&lt;=!= 比较两个对象的值。对象不必具有相同的类型。如果两者都是数字,则将它们转换为通用类型。否则,不同类型的对象总是比较不相等,并且顺序一致但随意。

【讨论】:

所以基本上一个元组大于一个列表,因为它以字母't'开头,不是吗? :) 它说“任意”。它们的顺序只是实现的产物,使用不同的解释器可能会有所不同。【参考方案3】:

因为不同类型的python对象是任意比较的(至少在python 2.7中任意表示“按其类型名称按字母顺序排列”)。因此,tuple 将始终是 &gt;,然后是 list

The Python (2.7) Language Reference - 5.9. Comparisons:

大多数其他内置类型的对象比较不相等,除非它们是 同一个对象;一个对象是否被认为更小的选择 或大于另一个是任意但始终在 一个程序的一次执行。

比较不同类型的对象的规则不应该是 依靠;它们可能会在该语言的未来版本中发生变化。

This is the c function for comparing python objects(来自Python 2.7 source):

default_3way_compare(PyObject *v, PyObject *w)

    int c;
    const char *vname, *wname;

    if (v->ob_type == w->ob_type) 
        /* When comparing these pointers, they must be cast to
         * integer types (i.e. Py_uintptr_t, our spelling of C9X's
         * uintptr_t).  ANSI specifies that pointer compares other
         * than == and != to non-related structures are undefined.
         */
        Py_uintptr_t vv = (Py_uintptr_t)v;
        Py_uintptr_t ww = (Py_uintptr_t)w;
        return (vv < ww) ? -1 : (vv > ww) ? 1 : 0;
    

    /* None is smaller than anything */
    if (v == Py_None)
        return -1;
    if (w == Py_None)
        return 1;

    /* different type: compare type names; numbers are smaller */
    if (PyNumber_Check(v))
        vname = "";
    else
        vname = v->ob_type->tp_name;
    if (PyNumber_Check(w))
        wname = "";
    else
        wname = w->ob_type->tp_name;
    c = strcmp(vname, wname);
    if (c < 0)
        return -1;
    if (c > 0)
        return 1;
    /* Same type name, or (more likely) incomparable numeric types */
    return ((Py_uintptr_t)(v->ob_type) < (
        Py_uintptr_t)(w->ob_type)) ? -1 : 1;

要查看的主要部分是行(接近末尾):

else
    wname = w->ob_type->tp_name;
c = strcmp(vname, wname);

【讨论】:

【参考方案4】:

任意实现选择。这是 Python 3 中的 TypeError。

【讨论】:

以上是关于Python 中的一个奇怪现象的主要内容,如果未能解决你的问题,请参考以下文章

Windows Phone 应用程序上 ShakeGesture 库中的奇怪现象

一个关于ExecutorService shutdownNow时很奇怪的现象

Javascript和DOM的一个奇怪现象

一次网络不通的奇怪现象处理

Apache RocketMQ:一个奇怪的现象

three.js 平面的奇怪现象