Согласно документации id()
, id
гарантированно будет уникальным
- за время жизни конкретного объекта и
- в конкретном экземпляре интерпретатора
Таким образом, сравнение id
s небезопасно, если только вы не гарантируете, что оба объекта, чьи id
s взяты, все еще живы во время сравнения (и связаны с тем же Экземпляр интерпретатора Python, но вам нужно постараться, чтобы это стало ложным).
Именно это и делает is
, что делает сравнение id
излишним. Если по какой-либо причине вы не можете использовать синтаксис is
, всегда есть operator.is_
.
Теперь, , является ли объект еще живым во время сравнения, не всегда очевидно (а иногда и не -очевидный):
Доступ к некоторым атрибутам (например, привязанные методы объекта ) каждый раз создает новый объект. Таким образом, результат id
может или может не совпадать при доступе к каждому атрибуту.
* * Пример тысячу сорок четыре: * * 1045
>>> class C(object): pass
>>> c=C()
>>> c.a=1
>>> c.a is c.a
True # same object each time
>>> c.__init__ is c.__init__
False # a different object each time
# The above two are not the only possible cases.
# An attribute may be implemented to sometimes return the same object
# and sometimes a different one:
@property
def page(self):
if check_for_new_version():
self._page=get_new_version()
return self._page
Если объект создан в результате вычисления выражения и нигде не сохранен, он немедленно отбрасывается, 1 и любой объект, созданный после этого, может занять его id
.
Это верно даже для одной строки кода. Например. результат id(create_foo()) == id(create_bar())
не определен.
* * Пример тысяча шестьдесят один:
>>> id([]) #the list object is discarded when id() returns
39733320L
>>> id([]) #a new, unrelated object is created (and discarded, too)
39733320L #its id can happen to be the same
>>> id([[]])
39733640L #or not
>>> id([])
39733640L #you never really know
Из-за вышеуказанных требований безопасности при сравнении id
с сохранение id
вместо объекта не очень полезно, так как в любом случае необходимо сохранить ссылку на сам объект - чтобы гарантировать, что он остается живым. Также нет никакого увеличения производительности: реализация is
так же проста, как сравнение указателей .
Наконец, в качестве внутренней оптимизации (и деталей реализации, так что она может отличаться в разных реализациях и выпусках), CPython повторно использует некоторые часто используемые простые объекты неизменяемых типов. На момент написания статьи это включает маленькие целые числа и некоторые строки . Поэтому, даже если вы получили их из разных мест, их id
могут совпадать.
Это (технически) не нарушает вышеприведенных id()
обещаний уникальности документации: повторно используемый объект остается живым в течение всех повторных использований.
Это также не имеет большого значения, потому что, если две переменные указывают на один и тот же объект или нет, практично знать, является ли объект изменчивым: если две переменные указывают на один и тот же изменяемый объект, мутирует одна (неожиданно) ) поменяй другой тоже . Неизменяемые типы не имеют такой проблемы, поэтому для них не имеет значения, указывают ли две переменные на два идентичных объекта или на один и тот же.
1 Иногда это называется "неназванное выражение".