Python 中的一个奇怪现象
Posted
技术标签:
【中文标题】Python 中的一个奇怪现象【英文标题】:A curious occurrence in Python 【发布时间】:2011-12-20 14:30:57 【问题描述】:由于某种原因,tuple > list
形式的 Python 2.7 表达式返回 True
,但 tuple < list
和 tuple == list
返回 False
。这是为什么呢?
这个观察无论如何都不是我的原创。
【问题讨论】:
见Why is ''>0 True in Python?和Why does 4 < '3' return True in Python 2? 【参考方案1】:tuple
和 list
不是同一类型。当比较不同类型的值并且没有定义跨这些类型工作的比较器时,Python 做了一些令人惊讶的事情。它比较类名称的字典顺序:
>>> class Coffee(object):
... pass
...
>>> class Tea(object):
... pass
...
>>> c = Coffee()
>>> t = Tea()
>>> c > t
False
>>> c == t
False
>>> c < t
True
>>>
谢天谢地,在 python 3 中,这种情况消失了,比较这些类型会引发异常。
【讨论】:
"tuple
和 lis
t 不是同一类型。"错了,它们都是type
类型。
@Sven Marnach: 可能我的语法不是很清楚,list
和tuple
这两种类型有 相同的类型,type(list) is type(tuple)
但它们不是同一类型,type(list) is type and type(tuple) is type and list is not tuple
tuple
和 list
显然是不同的类型,但这对于这个问题完全无关紧要。 OP 询问了 list < tuple
等的奇怪结果,但您的回答一直在谈论比较不同类型的值,即使在示例代码中也是如此。这绝对不是你的语法不清楚的问题——我的意思是这个答案没有抓住重点(尽管只是稍微)。您解释了不同类型的值按其类型名称的字典顺序排序——这与比较 list
和 tuple
有什么关系?
我们对问题的解释不同;我理解 Alexei 的“forms of the form tuple > list”(强调我的)'list' 和 'tuple' 词是元句法变量,代表那些类型的值,而不是键入内置list
或tuple
的值。
你是对的——我没有想到你阅读问题的方式。这是有道理的,感谢您的澄清【参考方案2】:
来自the doc:
运算符
<
、>
、==
、>=
、<=
和!=
比较两个对象的值。对象不必具有相同的类型。如果两者都是数字,则将它们转换为通用类型。否则,不同类型的对象总是比较不相等,并且顺序一致但随意。
【讨论】:
所以基本上一个元组大于一个列表,因为它以字母't'开头,不是吗? :) 它说“任意”。它们的顺序只是实现的产物,使用不同的解释器可能会有所不同。【参考方案3】:因为不同类型的python对象是任意比较的(至少在python 2.7中任意表示“按其类型名称按字母顺序排列”)。因此,tuple
将始终是 >
,然后是 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 库中的奇怪现象