Я хотел бы иметь возможность проверить, являются ли два вызываемых объекта одинаковыми или нет. Я бы предпочел идентификационную семантику (используя оператор "is" ), но я обнаружил, что когда задействованы методы, происходит что-то другое.
#(1) identity and equality with a method
class Foo(object):
def bar(self):
pass
foo = Foo()
b = foo.bar
b == foo.bar #evaluates True. why?
b is foo.bar #evaluates False. why?
Я воспроизвел это как с Python 2.7, так и с 3.3 (CPython), чтобы убедиться, что это не деталь реализации старой версии. В других случаях тестирование идентичности работает как ожидалось (сеанс интерпретатора продолжался сверху):
#(2) with a non-method function
def fun(self):
pass
f = fun
f == fun #evaluates True
f is fun #evaluates True
#(3) when fun is bound as a method
Foo.met = fun
foo.met == fun #evaluates False
foo.met is fun #evaluates False
#(4) with a callable data member
class CanCall(object):
def __call__(self):
pass
Foo.can = CanCall()
c = foo.can
c == foo.can #evaluates True
c is foo.can #evaluates True
В соответствии с вопросом Как Python отличает функцию обратного вызова, которая является членом класса?, функция обертывается при привязке как метод. Это имеет смысл и согласуется с рассмотренным выше случаем (3).
Есть ли надежный способ привязать метод к другому имени, а затем сравнить его как объект, подлежащий вызову, или обычную функцию? Если "==" делает трюк, как это работает? Почему "==" и "есть" ведут себя по-другому в случае (1) выше?
Edit
Как отметил @Claudiu, ответ на Почему методы не имеют ссылочного равенства? также является ответом на этот вопрос.