Python 2何时将一个函数视为“大于”或“小于”另一个函数?

时间:2014-03-10 19:20:42

标签: python python-2.7 comparison

我刚刚发现使用运算符><>=<=比较任意函数在Python中是合法的。这看起来有点傻;我一半期望这样的比较永远是False(或抛出异常),但文档说:"Most other objects of built-in types compare unequal unless they are the same object; the choice whether one object is considered smaller or larger than another one is made arbitrarily but consistently within one execution of a program."

所以我做了一些实验,这意味着可能在这里定义函数的顺序很重要:

>>> def g():
    pass

>>> def y():
    pass

>>> g > y
False
>>> y > g
True
>>> def r():
    pass

>>> g > r
False
>>> r > g
True
>>> y > r
False
>>> r > y
True
>>> def barfoo():
    pass

>>> barfoo > r > y > g
True

我尝试追踪源代码(在这里注意到我现在已经超出了我的深度,拥有了两个月的C经验)。 This answer引导我Python/ceval.c,它似乎使用PyObject_RichCompare()处理这些比较运算符(第4640行)。我找不到该函数的定义,只有a PEP,这就是我被卡住的地方。

我如何预测这些看似荒谬的操作的结果? (只要我们在这里......我为什么要这样做?)

加成:

>>> unicode > super > object > type > tuple > str > basestring > slice > frozenset > set > xrange > memoryview > long > list > int > staticmethod > classmethod > float > file > reversed > enumerate > dict > property > complex > bytearray > buffer > bool > zip > vars > unichr > sum > sorted > setattr > round > repr > reload > reduce > raw_input > range > pow > ord > open > oct > next > min > max > map > locals > len > iter > issubclass > isinstance > intern > input > id > hex > hash > hasattr > globals > getattr > format > filter > execfile > eval > divmod > dir > delattr > compile > coerce > cmp > chr > callable > bin > apply > any > all > abs > __import__ > help
True

4 个答案:

答案 0 :(得分:4)

在python2中,这些类型的比较是基于对象的id()的值完成的:

In [1]: def g():
   ...:     pass

In [2]: def y():
   ...:     pass

In [3]: g > y
Out[3]: True

In [4]: id(g)
Out[4]: 55898312

In [5]: id(y)
Out[5]: 54420736

id()的值通常取决于函数对象的内存地址,这可能取决于垃圾收集器的先前历史记录之类的任意内容。可能由于这个原因,Python的开发人员删除了这个功能,因此比较Python3中的函数现在会出错:

In [3]: g > y
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/home/xxx/<ipython-input-3-9ebc8ff65838> in <module>()
----> 1 g > y

TypeError: unorderable types: function() > function()

在python 3中,相等性的比较仍然是合法的,因为它不依赖于id()的任意值:

In [4]: g == y
Out[4]: False

In [5]: g != y
Out[5]: True

答案 1 :(得分:4)

线索在:

  

任意但始终如一

Python通过id进行比较,所以如果

str > list

然后

id(str) > id(list)

(我得到False奖金!)

答案 2 :(得分:2)

首先,重要的是要注意这种行为在Python 3中更合乎逻辑:

>>> def f(): pass
...
>>> def g(): pass
...
>>> f < g
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: function() < function()

至于Python 2中的行为,您已经引用了relevant documentation

  

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

这里的关键是订单是任意的,所以回答你的问题:

  

我如何预测这些看似荒谬的操作的结果?

不要试图,文档明确声明您所遵守的任何顺序都不能依赖,并且可能因不同的解释器,版本甚至同一程序的不同执行而发生变化。

至于如何在CPython中实际实现它,是基于函数的id(),它本质上是内存中的一个地址。见How does python compare functions?

答案 3 :(得分:1)

我相当肯定†它使用built-in function id,它来自其文档字符串:&#34;返回[s]对象的标识。这保证在同时存在的对象中是唯一的。 (提示:它是对象的内存地址。)&#34;

这与您从文档中为不等式运算符找到的不变量一致。

在我的系统上,它似乎取决于您定义函数的顺序。一个例子:

In [1]: def g():
   ...:     pass
   ...: 
In [2]: def y():
   ...:     pass
   ...: 
In [3]: g > y
Out[3]: False
In [4]: y > g
Out[4]: True
In [5]: (id(g), id(y))
Out[5]: (171432676, 171432844)
In [6]: id(g) > id(y)
Out[6]: False

对战:

In [1]: def y():
   ...:     pass
   ...: 
In [2]: def g():
   ...:     pass
   ...: 
In [3]: g > y
Out[3]: True
In [4]: y > g
Out[4]: False
In [5]: (id(g), id(y))
Out[5]: (165088140, 165087972)
In [6]: id(g) > id(y)
Out[6]: True

这与其私有堆上的Python allocates memory for dynamic objects如何密切相关,但作为the docs themselves state,它是用于比较不直观可订购的对象(如函数)的任意度量

†至少对于CPython实现