在实践中我可以在多大程度上依赖于对象的id()
及其唯一性?例如:
id(a) == id(b)
是指a is b
还是相反?相反吗?id
保存在某个地方以便以后使用(例如,放入某个注册表而不是对象本身)有多安全?(作为对Canonicals for Python: are objects with the same id() the same object, `is` operator, unbound method objects的响应而建议的规范)
答案 0 :(得分:7)
根据id()
documentation,只能保证id
是唯一的
这样,比较id
是不安全的,除非您还以某种方式确保在比较时两个被id
拍摄的对象仍然存在(并且与同一个Python解释器实例相关联,但是您需要真正尝试使它变为假)。
is
正是这样做的-这使得比较id
是多余的。如果由于某种原因而无法使用is
语法,那么总会有operator.is_
。
现在,在比较时对象是否还活着并不总是显而易见的(有时甚至是非明显):
访问某些属性(例如bound methods of an object)每次创建一个新对象。因此,结果的id
可能每次属性访问都不同。
示例:
>>> 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
implementation is as simple as comparing pointers。
最后,作为内部优化(和实现细节,因此实现和发行版之间可能会有所不同),CPython重用了一些经常使用的不可变类型的简单对象。在撰写本文时,其中包括small integers和some strings。因此,即使您从不同的地方获得它们,它们的id
也可能重合。
(技术上)这没有违反上述id()
文档的唯一性保证:重用的对象在所有重用中都保持活动状态。
这也不是什么大问题,因为两个变量是否指向同一个对象只知道该对象是否可变:if two variables point to the same mutable object, mutating one will (unexpectedly) change the other, too。不可变类型没有这个问题,因此对于它们来说,两个变量指向两个相同的对象还是指向同一对象都没有关系。
1 有时,这称为“未命名表达式”。