Как операторы сравнения Python <и> работают с именем функции в качестве операнда?

Перейдите в эту проблему (в Python 2.7.5) с небольшой опечаткой:

def foo(): return 3
if foo > 8:
    launch_the_nukes()

Давай, я случайно взорвал Луну.

Я понимаю, что E > F эквивалентен (E).__gt__(F) и для хорошо выполненных классов (таких как встроенные), эквивалентных (F).__lt__(E).

Если нет операторов __lt__ или __gt__, то я думаю, что Python использует __cmp__.

Но ни один из этих методов не работает с объектами function, пока работают операторы < и >. Что происходит под капотом, что делает это возможным?

>>> foo > 9e9
True
>>> (foo).__gt__(9e9)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute '__gt__'
>>> (9e9).__lt__(foo)
NotImplemented

Ответ 1

Но ни один из этих методов не работает с объектами функций, в то время как < и > операторы работают. Что происходит под капотом, что делает это возможным?

В случае любого другого разумного сравнения CPython в серии 2.x сравнивается на основе имени типа. (Это задокументировано как деталь реализации, хотя есть некоторые интересные исключения, которые можно найти только в источнике.) В серии 3.x это приведет к исключению.

Спецификация Python помещает определенное ограничение на поведение в 2.x; сравнение по типу имени не является единственным разрешенным поведением, а другие реализации могут делать что-то еще. На это нельзя положиться.