简体   繁体   English

为什么0 <()在Python中评估为True?

[英]Why does 0 < () evaluate to True in Python?

I inadvertently typed time.clock<() with the Python 2.7 interpreter response being: True . 我无意中输入了time.clock<() ,而Python 2.7解释器响应为: True The following code exemplifies the behavior: 下面的代码举例说明了此行为:

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

Moreover: 此外:

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

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

In contrast: 相反:

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

Question: Besides why, is there a practical meaning or purpose of an empty list , tuple or dict evaluating as if were greater than any number? 问题: 除了为什么,还有一个空listtupledict评估是否大于任何数字是否有实际意义或目的?


Update : 更新

  • Viktor pointed out that memory-addresses are compared by default: Viktor指出,默认情况下会比较内存地址:

    >>> map(lambda _:(id(0),'<',id(_)),((),[],{}, set([])))

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

Despite the seeming order, this is incorrect . 尽管顺序看似, 但这是不正确的


  • Martijn Pieters points out that: Martijn Pieters指出:

Without an explicit comparison operator defined, Python 2 compares by Numbers and Type-names, with numbers having the lowest precedence. 在没有定义显式比较运算符的情况下,Python 2会按数字和类型名称进行比较,数字优先级最低。

This does not hint at what exact internal methods are being invoked. 这并不暗示正在调用确切的内部方法。 See also this helpful but inconclusive SO thread : 另请参见此有用但不确定的SO线程

In an IPython 2.7.5 REPL 在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]

In Python 2, when comparing different types, python sorts numeric types before everything else, and between the rest sorts types by type name . 在Python 2中,当比较不同类型时,python将数字类型排在其他所有类型之前,其余之间按类型name对类型进行排序。

Thus, integers sort before tuples, but instances of class Foo will sort after instances of class Bar . 因此,整数在元组之前排序,但是Foo类的实例将 Bar类的实例之后排序。

Python 3 does away with this madness; Python 3消除了这种疯狂; comparing different types results in a TypeError instead: 比较不同类型会导致TypeError:

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

The Python set() type has overloaded the > operator by implementing the __gt__ or 'greater then' magic method; Python set()类型通过实现__gt__或'greater then'魔术方法来重载>运算符; it is called for the 1 < set() expression because the int type has no __lt__ , lower-then and Python tests the inverse in that case; 它被称为1 < set()表达式,因为int类型没有__lt__ ,请lower-then,然后在这种情况下,Python将测试逆向; after all, x < y is true if y > x is true. 毕竟,如果y > x为true,则x < y为true。

The set.__gt__() hook raises a TypeError when the other operand is not a set : 当另一个操作数不是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

The overloaded > (greater then) operator for sets is used to test if the left-hand operand is a proper superset of the right-hand operand . set的重载> (大于)运算符用于测试左侧操作数是否是右侧操作数的适当超集 (Technically, set objects implement the C-API PyTypeObject.tp_richcompare function, not the __gt__ hook directly, but the __gt__ hook translates to a tp_richcompare call in that case automatically). (在技术上, set对象实现了C-API PyTypeObject.tp_richcompare功能,而不是__gt__钩直接,但__gt__钩转换为一个tp_richcompare自动在这种情况下,呼叫)。

When an overloaded comparison method (one of .__lt__() , .__le__() , .__eq__() , . __ne__() , . __gt__() , . __ge__() , or . __cmp__() ) returns the NotImplemented singleton object this signals that the comparison is not supported and Python falls back to the default behaviour. 当一个重载比较方法(之一.__lt__() .__乐__() , .__le__() .__当量__() , .__eq__() 。__ne __() , . __ne__() 。__gt __() , . __gt__() 。__ge __() ,. __ge__() 。__cmp __() )返回NotImplemented Singleton对象此表示不支持该比较,并且Python恢复为默认行为。 This default behaviour, as already stated in How do Python comparison operators < and > work with a function name as an operand? Python比较运算符<和>如何将函数名称用作操作数所述,这种默认行为是? differs between Python 2 and 3. 在Python 2和3之间有所不同。

For Python 3, a comparison hook returning NotImplemented causes Python to raise TypeError : 对于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 is more stubborn and when NotImplemented is returned or no hooks have been implemented, the C code ends up in the default_3way_compare() C function , which: Python 2更顽固,当返回NotImplemented或未实现任何钩子时,C代码最终以default_3way_compare() C函数结尾:

  • Orders by memory addresses when the types of both objects are the same (line 768-776) 当两个对象的类型相同时,按内存地址排序(行768-776)
  • Orders None before anything (line 780-783) None任何命令(780-783行)
  • Orders numbers before other types ( PyNumber_Check tests set type name to empty, lines 786-793) 在其他类型之前订购数字( PyNumber_Check测试将类型名称设置为空,行786-793)
  • Orders by typename ( v->ob_type->tp_name and w->ob_type->tp_name in lines 786-793) 按类型名w->ob_type->tp_name行中的v->ob_type->tp_namew->ob_type->tp_name tp_name)
  • If the type names are the same, orders by memory address of the type objects (lines 800 and 801). 如果类型名称相同,则按类型对象的存储地址排序(第800和801行)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM