id()功能的Python文档指出以下内容:
这是一个整数,可以保证在此对象的生存期内唯一且恒定。具有不重叠生命周期的两个对象可能具有相同的
id()值。CPython实现细节:这是对象在内存中的地址。
虽然,下面的代码片段显示了id重复的。由于我没有明确del显示对象,因此我假设它们都是活动的并且是唯一的(我不知道不重叠的含义)。
>>> g = [0, 1, 0]
>>> for h in g:
... print(h, id(h))
...
0 10915712
1 10915744
0 10915712
>>> a=0
>>> b=1
>>> c=0
>>> d=[a, b,c]
>>> for e in d:
... print(e, id(e))
...
0 10915712
1 10915744
0 10915712
>>> id(a)
10915712
>>> id(b)
10915744
>>> id(c)
10915712
>>>
Run Code Online (Sandbox Code Playgroud)
id不同对象的值如何相同?是因为值0(class的对象int)是一个常量并且解释器/ C编译器进行了优化吗?
如果我要这样做a = c,那么我理解c与相同id,a因为它c只是对a(alias)的引用。我期望的对象a并c具有不同的id其它方式的值,但,如上所示,它们具有相同的值。
发生了什么?还是我看错了方向?
我希望id's for user-defined class'对象始终具有唯一性,即使它们具有完全相同的成员值。
有人可以解释这种行为吗?(我查看了其他询问的使用的问题id(),但它们将其引向其他方向)
编辑(09/30/2019):
为了延长我已经写了,我跑在不同的终端Python解释和检查id的为0上所有的人,他们都是一模一样的(对于相同的解释); 不同解释的多个实例有相同id的0。Python2与Python3具有不同的值,但是相同的Python2解释器具有相同的id值。
我的问题是因为id()的文档中没有说明任何此类优化,这似乎具有误导性(我不希望每个怪癖都被注意到,但是CPython注释旁边的一些注释会很好)...
编辑2(09/30/2019):
问题出在理解这种行为并知道是否有任何钩子以类似方式优化用户定义类(通过修改__equals__方法以识别两个对象是否相同;也许会指向内存中的相同地址,即相同的地址)。id或使用某些metaclass属性)
标识在对象的生存期内是唯一的。如果删除对象,则新对象可以获取相同的ID。当引用计数降至零时,CPython将立即删除它们。仅需要垃圾回收器来破坏参考周期。
CPython还可以缓存和重用某些不可变的对象,例如小的整数和由文字(它们是有效的标识符)定义的字符串。这是您不应该依赖的实现细节。通常认为is对此类对象使用检查是不适当的。
该规则有某些例外,例如,在将可能被插入的字符串与正常==运算符进行比较之前,使用is-check 作为优化是可以的。该dict内建使用此策略进行查找,使他们标识符更快。
a is b or a == b # This is OK
Run Code Online (Sandbox Code Playgroud)
如果字符串恰好是实习,然后上面可以用一个简单的ID比较,而不是较慢的字符一个字符比较返回true,但它仍返回true当且仅当a == b(因为如果a is b那么a == b也必须是真实的)。
感谢您的回答,您能否详细说明用户定义对象的唯一性,它们始终是唯一的吗?
任何对象的ID (无论是否由用户定义)在对象的生存期内都是唯一的。区分对象和变量很重要。可能有两个或多个变量引用同一个对象。
>>> a = object()
>>> b = a
>>> c = object()
>>> a is b
True
>>> a is c
False
Run Code Online (Sandbox Code Playgroud)
缓存优化意味着在某些情况下,您可能天真地认为一个新对象并不一定能获得一个新对象,但这丝毫不违反ID的唯一性保证。内置类型喜欢int和str可能有一些缓存优化,但是它们遵循完全相同的规则:如果它们同时存在并且其ID相同,则它们是同一对象。
缓存不是内置类型独有的。您可以为自己的对象实现缓存。
>>> def the_one(it=object()):
... return it
...
>>> the_one() is the_one()
True
Run Code Online (Sandbox Code Playgroud)
甚至用户定义的类也可以缓存实例。例如,此类仅使自己成为一个实例。
>>> class TheOne:
... _the_one = None
... def __new__(cls):
... if not cls._the_one:
... cls._the_one = super().__new__(cls)
... return cls._the_one
...
>>> TheOne() is TheOne() # There can be only one TheOne.
True
>>> id(TheOne()) == id(TheOne()) # This is what an is-check does.
True
Run Code Online (Sandbox Code Playgroud)
请注意,每个构造表达式求值的对象的ID彼此相同。但是此ID 是对象唯一的。这两个表达式都引用相同的对象,因此它们当然具有相同的id。
上面的类仅保留一个实例,但是您也可以缓存其他一些实例。可能是最近使用过的实例,或者以您期望是通用的方式配置的实例(如int一样)等。