Рассмотрим этот код:
class Person(object):
def sayHello(self):
return 'Hello'
print(Person().sayHello is Person().sayHello)
Я ожидаю, что он покажет True. Почему он показывает False?
Рассмотрим этот код:
class Person(object):
def sayHello(self):
return 'Hello'
print(Person().sayHello is Person().sayHello)
Я ожидаю, что он покажет True. Почему он показывает False?
Методы on привязаны к экземплярам в время выполнения. Когда вы запустите следующий код:
print(Person().sayHello is Person().sayHello)
вы создаете два экземпляра и каждый раз, когда у вас есть другой адрес памяти.
>>> Person().sayHello
<bound method Person.sayHello of <__main__.Person object at 0x7fbe90640410>>
>>> Person().sayHello
<bound method Person.sayHello of <__main__.Person object at 0x7fbe90640490>>
Примечание: Все, что у нас есть в Python, - это время выполнения; не существует отдельного времени компиляции.
Это два разных экземпляра одного класса. Функции sayHello
являются связанными методами.
То есть, если у вас есть экземпляр класса:
p = Person()
и вы найдете в нем атрибут:
p.sayHello
тогда Python сначала рассмотрит фактические атрибуты экземпляра, и если он не найдет здесь атрибут, он рассмотрит класс. Если он находит метод класса этого имени, он превращает его в связанный метод, связанный с этим экземпляром. Это волшебство, которое приводит к тому, что экземпляр объекта передается как первый аргумент (self
) в sayHello
.
Итак, Person().sayHello is Person().sayHello
создает два экземпляра, создает два разных метода привязки, основанных на том же методе, который определен в классе, и поэтому is
возвращает False
, потому что они разные методы.
Я собираюсь предположить, что вы намеренно сравниваете сами объекты метода, а не то, что вы действительно хотели сравнить выходные строки и просто забыли поставить ()
после sayHello
.
Попробуйте этот эксперимент:
a = Person()
b = Person()
a.sayHello
b.sayHello
Вы увидите, что a.sayHello
отображается как нечто вроде
<bound method Person.sayHello of <__main__.Person instance at 0x102cc8ef0>>
... тогда как b.sayHello
отображается аналогично, но с другим указателем родительского экземпляра:
<bound method Person.sayHello of <__main__.Person instance at 0x102d31908>>
Связанный метод одного экземпляра a Person
сам по себе является другим экземпляром (метода) из связанного метода с тем же именем из другого экземпляра Person
. Вы можете подтвердить это с помощью id(a.sayHello)
и id(b.sayHello)
, которые возвращают хэш-идентификаторы двух соответствующих методах привязки - они будут разными. Поскольку ваш код Person().sayHello is Person().sayHello
создает два разных экземпляра Person
"на лету", ситуация такая же, как и в примерах с именованными экземплярами a
и b
.
Это было бы True
, если вы вызвали sayHello
:
print(Person().sayHello() is Person().sayHello())
В вашем коде вы фактически сравниваете методы с объектами и проверяете, имеют ли они одинаковый идентификатор (которого у них нет). Также обратите внимание на разницу между:
"Hello" is "Hello"
и
"Hello" == "Hello"
Во-первых, вы сравниваете идентичность объектов (что является одним и тем же из-за повторного использования строки, вызовите id("Hello")
несколько раз, чтобы увидеть это). Во втором случае вы сравниваете содержимое строк, чтобы убедиться, что они равны (то есть имеют одинаковые символы). Теперь те же строки будут иметь одинаковые идентификаторы, но я не уверен, что это допущение выполняется во всех реализациях Python.
Оператор означает, что обе переменные указывают на один и тот же объект вместо того же значения. См. Вопрос "Переполнение стека" Понимание Python "является" оператором.
Если вам нужно выражение, которое возвращает True
, вы можете попробовать следующее:
print(Person.sayHello is Person.sayHello)
Чтобы добавить к путанице, выполните:
>>> say = Person.sayHello
>>> say()
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
say()
TypeError: sayHello() missing 1 required positional argument: 'self'
и даже:
>>> say(say)
'Hello'
>>> say(None)
'Hello'
>>>
Это происходит потому, что:
>>> say
<function Person.sayHello at 0x02AF04B0>
say
относится к Person.sayHello
, который является функцией, которая может быть вызвана, но которая нуждается в параметре, но в этом конкретном случае параметр не имеет значения.
Теперь, если вы не хотите продолжать поставлять бесполезный параметр, вы можете связать его автоматически:
>>> p=Person()
>>> p.sayHello()
'Hello'