【问题标题】:Why does 0 < () evaluate to True in Python?为什么 0 < () 在 Python 中评估为 True?
【发布时间】:2013-09-02 05:37:06
【问题描述】:

我无意中输入了time.clock&lt;(),Python 2.7 解释器的响应是:True。以下代码举例说明了该行为:

>>> repr(time.clock)
'<built-in function clock>'
>>> time.clock<()
True

此外:

>>> import sys
>>> sys.maxint < ()
True

>>> map(lambda _:0<_,((),[],{}))
[True, True, True]

相比之下:

>>> 1<set(())
TypeError: can only compare to a set

问题:除了为什么之外,空的listtupledict 评估好像大于任何数字有实际意义或目的吗?


更新

  • Viktor 指出默认情况下会比较内存地址:

    &gt;&gt;&gt; map(lambda _:(id(0),'&lt;',id(_)),((),[],{}, set([])))

    [(31185488L, '<', 30769224L), (31185488L, '<', 277144584L), (31185488L, '<', 279477880L), (31185488L, '<', 278789256L)]

尽管看起来顺序,这是不正确的


  • Martijn Pieters 指出:

如果没有明确定义比较运算符,Python 2 会比较 数字和类型名称,数字的优先级最低。

这并不暗示正在调用的确切内部方法。另请参阅这很有帮助但inconclusive SO thread

在 IPython 2.7.5 REPL 中

>>> type(type(()).__name__)
Out[15]: str

>>> type(()) < 10
Out[8]: False
>>> 10 < type(())
Out[11]: True
#as described
>>> type(()) < type(())
Out[9]: False
>>> type(()) == type(())
Out[10]: True

However:
>>> 'somestr' .__le__(10)
Out[20]: NotImplemented
>>> 'somestr' .__lt__(10)
Out[21]: NotImplemented

>>> int.__gt__
Out[25]: <method-wrapper '__gt__' of type object at 0x1E221000>
>>> int.__lt__
Out[26]: <method-wrapper '__lt__' of type object at 0x1E221000>

>>> int.__lt__(None)
Out[27]: NotImplemented
    #.....type(...), dir(...), type, dir......
#An 'int' instance does not have an < operator defined
>>> 0 .__lt__
Out[28]: AttributeError: 'int' object has no attribute '__lt__'

#int is actually a subclass of bool
>>>int.__subclasses__()
Out: [bool]
#str as the fallback type for default comparisons
>>> type(''.__subclasshook__)
Out[72]: builtin_function_or_method
>>> dir(''.__subclasshook__)
Out[73]: 
['__call__',
 '__class__',
 '__cmp__',
 '__delattr__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__le__',
 '__lt__',
 '__module__',
 '__name__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__self__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__']
#IPython is subclassing 'str' 
>>> str.__subclasses__()
Out[84]: [IPython.utils.text.LSString]

【问题讨论】:

  • 请注意,在 python3 中,所有这些比较都会引发 TypeError: &gt;&gt;&gt; 0 &lt; () Traceback (most recent call last): File "&lt;stdin&gt;", line 1, in &lt;module&gt; TypeError: unorderable types: int() &lt; tuple()
  • 维克托的回答不正确。
  • @Bakuriu 我也觉得应该如此。谢谢你的安慰。
  • 这是在 python3 中通过向后不兼容的更改修复的尴尬事情之一(并且有充分的理由)。如果您没有令人信服的理由继续使用 python2(例如,无法升级盒子,或缺少依赖项),我强烈建议您开始使用 python3(但确实阅读各种“新功能”)

标签: python collections comparison boolean logic


【解决方案1】:

在 Python 2 中,当比较不同的类型时,python 将数值类型排在其他所有类型之前,而在其余类型之间按类型名称进行排序。

因此,整数在元组之前排序,但Foo 类的实例将在Bar 类的实例之后 排序。

Python 3 消除了这种疯狂;比较不同的类型会导致 TypeError:

>>> 10 < ()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < tuple()

Python set() 类型通过实现__gt__ 或“大于”魔术方法重载了&gt; 运算符;调用 1 &lt; set() 表达式是因为 int 类型没有 __lt__,在这种情况下,Python 会测试相反的情况;毕竟,如果y &gt; x 为真,则x &lt; y 为真。

当另一个操作数不是 set 时,set.__gt__() 钩子会引发 TypeError

>>> 1 .__lt__(set())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__lt__'
>>> set().__gt__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only compare to a set

集合的重载&gt;(大于)运算符用于测试左侧操作数是否为proper superset of the right-hand operand。 (从技术上讲,set 对象实现了 C-API PyTypeObject.tp_richcompare 函数,而不是直接实现 __gt__ 钩子,但 __gt__ 钩子在这种情况下会自动转换为 tp_richcompare 调用。

当重载的比较方法(.__lt__(), .__le__(), .__eq__(), . __ne__(), . __gt__(), . __ge__(), or . __cmp__() 之一)返回 NotImplemented 单例对象时,这表示不支持比较,Python 会退回到默认行为。正如How do Python comparison operators < and > work with a function name as an operand? 中所述,这种默认行为在 Python 2 和 3 之间有所不同。

对于 Python 3,返回 NotImplemented 的比较挂钩会导致 Python 引发 TypeError

>>> class Foo():
...     def __lt__(self, other): return NotImplemented
... 
>>> Foo() < Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: Foo() < Foo()

Python 2 更加顽固,当返回 NotImplemented 或未实现任何钩子时,C 代码最终会出现在 default_3way_compare() C function 中,即:

  • 当两个对象的类型相同时按内存地址排序(第 768-776 行)
  • 先订购None(第 780-783 行)
  • 在其他类型之前订购编号(PyNumber_Check 测试将类型名称设置为空,第 786-793 行)
  • 按类型名称排序(第 786-793 行中的v-&gt;ob_type-&gt;tp_namew-&gt;ob_type-&gt;tp_name
  • 如果类型 names 相同,则按类型对象的内存地址排序(第 800 和 801 行)。

【讨论】:

  • 另外,set 示例失败,因为 &lt; 不是集合的小于运算符,它被视为“是子集”运算符,这显然不是t 对未设置的操作数有意义。 (我相信 python 文档在某处明确指出该语言没有定义 &lt;&gt; 等的语义,因此存在这种差异)
  • @Bakuriu:我在解释 lt 代表什么,而不是现在在集合中使用运算符。
  • @MartijnPieters 谢谢。我仍然无法放置比较步骤。请帮助我,作为您长期的 Pythionist,我很乐意接受您的回答。另请参阅我的更新。
  • @LoSauer:男孩,你在仙境中挖了一个洞,不是吗?有时间我会看看我能做些什么。
猜你喜欢
  • 2019-04-24
  • 2014-01-05
  • 2019-06-30
  • 2013-11-11
  • 2013-05-03
  • 1970-01-01
  • 2014-06-17
  • 2019-05-24
  • 2012-09-23
相关资源
最近更新 更多