id()
встроенная функция дает...
целое число (или длинное целое), который, как гарантируют, будет уникальным и постоянным для этого объекта в течение его времени жизни.
is
оператор, вместо этого, дает...
объектные идентификационные данные
Итак, почему возможно иметь два объекта, которые имеют то же id
но возвратитесь False
к is
проверить? Вот пример:
>>> class Test():
... def test():
... pass
>>> a = Test()
>>> b = Test()
>>> id(a.test) == id(b.test)
True
>>> a.test is b.test
False
Больше беспокоящегося примера: (продолжающееся вышеупомянутое)
>>> b = a
>>> b is a
True
>>> b.test is a.test
False
>>> a.test is a.test
False
Однако:
>>> new_improved_test_method = lambda: None
>>> a.test = new_improved_test_method
>>> a.test is a.test
True
>>> b.test is a.test
False
>>> a.test is a.test
False
Методы создаются "на лету" каждый раз, когда вы их просматриваете. Функциональный объект (который всегда является одним и тем же объектом) реализует протокол дескриптора , а его __ get __
создает связанный объект метода. Обычно два связанных метода не могут быть одним и тем же объектом.
>>> id(a.test) == id(b.test)
True
>>> a.test is b.test
False
Этот пример обманчив. Результат первого только Истинный
по совпадению. a.test
создает связанный метод и собирает мусор после вычисления id (a.test)
, потому что на него нет никаких ссылок. (Обратите внимание, что вы цитируете документацию, в которой говорится, что идентификатор является «уникальным и постоянным для этого объекта в течение его жизни » (выделено мной).) b.test
бывает , чтобы иметь тот же идентификатор, что и у связанного метода, который у вас был раньше, и это разрешено, потому что сейчас у других объектов нет такого же идентификатора.
Обратите внимание, что вы должны редко использовать is
и еще реже использовать id
. id (foo) == id (bar)
всегда неверен.
Что касается вашего нового примера, надеюсь, вы теперь понимаете, что он делает:
>>> new_improved_test_method = lambda: None
>>> a.test = new_improved_test_method
>>> a.test is a.test
True
В этом случае мы не создаем методы на лету из функций класса, автоматически связывающих себя и возвращающих связанные объекты методов. В этом случае вы просто сохраняете функцию как атрибут экземпляра. При поиске ничего особенного не происходит (дескрипторы вызываются только при поиске атрибута класса), поэтому каждый раз, когда вы просматриваете атрибут, вы получаете исходный объект, который вы сохранили.