Очень странное поведение оператора "есть" с методами

Почему первый результат False, если он не был True?

>>> from collections import OrderedDict
>>> OrderedDict.__repr__ is OrderedDict.__repr__
False
>>> dict.__repr__ is dict.__repr__
True

Ответ 1

Для пользовательских функций в Python 2 создаются по запросу безграничные и связанные методы, используя протокол дескриптора; OrderedDict.__repr__ - такой объект метода, поскольку завернутая функция реализована как функция pure-Python.

Протокол дескриптора вызовет метод __get__ для объектов, которые его поддерживают, поэтому __repr__.__get__() вызывается всякий раз, когда вы пытаетесь получить доступ к OrderedDict.__repr__; для классов None (нет экземпляра) и сам объект класса. Поскольку вы получаете новый объект метода каждый раз при вызове метода __get__, is терпит неудачу. Это не тот же объект метода.

dict.__repr__ не является настраиваемой функцией Python, а функцией C и ее дескриптором __get__ по существу просто возвращает self при доступе к классу. Доступ к атрибуту дает один и тот же объект каждый раз, поэтому is работает:

>>> dict.__repr__.__get__(None, dict) is dict.__repr__  # None means no instance
True

Методы имеют атрибут __func__, ссылающийся на обернутую функцию, используют это для проверки подлинности:

>>> OrderedDict.__repr__
<unbound method OrderedDict.__repr__>
>>> OrderedDict.__repr__.__func__
<function __repr__ at 0x102c2f1b8>
>>> OrderedDict.__repr__.__func__.__get__(None, OrderedDict)
<unbound method OrderedDict.__repr__>
>>> OrderedDict.__repr__.__func__ is OrderedDict.__repr__.__func__
True

Python 3 устраняет несвязанные методы, function.__get__(None, classobj) возвращает сам объект функции (поэтому он ведет себя как dict.__repr__). Но вы увидите то же поведение с связанными методами, методами, полученными из экземпляра.

Ответ 2

Два OrderedDict.__repr__ не привязаны к одному и тому же объекту. Если вы попытаетесь:

 OrderedDict.__repr__ == OrderedDict.__repr__

вы увидите, что они имеют одинаковое значение.