Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does Python 2 consider one function "greater than" or "less than" another function? [duplicate]

I just discovered that it's legal in Python to compare arbitrary functions using the operators >, <, >= and <=. This seems a bit silly; I half expected such a comparison to always be False (or throw an exception), but the docs say: "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."

So I did a little experimenting, which implied that perhaps the order in which functions are defined is significant here:

>>> 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

I tried tracking down the source code (noting here that I'm way out of my depth at this point, having all of two months' experience with C). This answer led me to Python/ceval.c, which seems to handle these comparison operators using PyObject_RichCompare() (line 4640). I couldn't find a definition for that function, only a PEP, and that's where I'm stuck.

How might I predict the result of these seemingly nonsensical operations? (And as long as we're here... why would I want to?)

Bonus:

>>> 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
like image 455
Air Avatar asked Mar 10 '14 19:03

Air


2 Answers

In python2, these type of comparisons is done based on the value of id() of the object:

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

The value of id() normally depends on the memory address of the function object, which might depend on arbitrary things like the previous history of the garbage collector. Probably for this reason, Python's developers removed this functionality, so comparing functions in Python3 now gives an error:

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()

In python 3, comparison for equality is still legal, since it does not depend on the arbitrary value of id():

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

In [5]: g != y
Out[5]: True
like image 68
Bas Swinckels Avatar answered Oct 06 '22 11:10

Bas Swinckels


The clue is in:

arbitrarily but consistently

Python does the comparison by id, so if

str > list

then

id(str) > id(list)

(And I get False for your bonus!)

like image 25
jonrsharpe Avatar answered Oct 06 '22 12:10

jonrsharpe