在SQLAlchemy tutorial之后,我在我的控制台上入侵并获得了以下结果:
>>> ed_user
<User(name='ed', fullname='Ed Jones', password='edspassword')>
>>> id(ed_user)
139859764807552
>>> our_user
<User(name='ed', fullname='Ed Jones', password='edspassword')>
>>> id(our_user)
139859764807552
>>> ed_user is our_user
True # so ed_user and our_user is the same object
>>> id(ed_user) - id(our_user)
0 # not suprisingly, their ids (i.e. their position in memory) don't differ
>>> id(ed_user) is id(our_user)
False # WAT?!
>>> id(ed_user) == id(our_user)
True # okay, as integer values they are the same
>>> id(id(ed_user)) == id(id(our_user))
True # but their id's ids are also the same
为什么id(ed_user) is id(our_user)
False
?
答案 0 :(得分:4)
您正在创建整数,检查其id()
,然后再次丢弃整数。然后Python重新使用您创建的下一个整数的内存地址,因此它们的id()
值匹配。
来自id()
function documentation:
两个具有非重叠生命周期的对象可能具有相同的
id()
值。
Python对象的生命周期由引用计数决定;如果对象的引用数超过0,则它将保留在内存中,否则将被删除。表达式id()
中的内部id(id(our_user))
调用创建一个仅由堆栈引用的整数;它被传递给外部id()
调用,然后从堆栈中删除,之后没有任何引用,它会被再次丢弃。
如果您首先创建了对生成的整数值的引用,那么您发现它们不相同:
>>> a = b = []
>>> id(a) == id(b)
True
>>> a is b
True
>>> id_of_a, id_of_b = id(a), id(b)
>>> id_of_a == id_of_b
True
>>> id(id_of_a) == id(id_of_b)
False
但等待!对于小整数(从-5到256),Python只创建一个副本(实习),因此两个整数的标识将再次相同:
>>> small = 200
>>> small is 200
True
总而言之,除非您完全知道有来测试单个对象(对象标识),否则请坚持使用相等测试。这也适用于SQLAlchemy。
答案 1 :(得分:1)
让我们逐一查看您的结果,看看发生了什么:
>>> ed_user is our_user
True
所以情况就是如此。我们有两个变量,它们引用同一个对象。没什么特别的。你甚至可以通过ed_user = our_user = 'something'
来复制它。
>>> id(ed_user) == id(our_user)
True
由于两个变量都相同,因此id()
的返回值与两个变量匹配。显然,差异也是零。
>>> id(ed_user) is id(our_user)
False
现在这是有趣的地方。我们知道返回值匹配,但根据此检查,返回值不是相同的对象。 id()
返回一个整数,显然这两个整数并不相同。怎么可能?嗯,这很简单:Python只保留a small set of small numbers的固定ID。对于所有较大的数字,将根据需要创建新的整数对象(实际对象!)。所以在你的情况下,数字是139859764807552
。这肯定是一个很大的数字,因此Python将为id(ed_user)
调用,...和id(our_user)
调用创建一个整数对象。所以我们有两个不同的整数对象。当然,两个不同的对象永远不会完全相同。到目前为止一切都很好。
>>> id(id(ed_user)) == id(id(our_user))
True
现在它变得疯狂了。上面,我们有两个id()
调用返回了同时存在的整数对象(因为这是比较所必需的)。现在,id()
保证我们永远不会为同时存在的两个不同对象返回相同的整数。这是前一次调用中的情况,这就是为什么我们最终得到两个不同的整数对象(具有相同的值)。
但是在这里,一切都有所不同:我们首先调用id(ed_user)
,这为我们提供了一个int对象(我们称之为a
)来获取值139859764807552
。然后我们在其上调用id()
并获取id为a
的int对象;我们称之为id_a
。此时,a
不再被引用,也不需要进行比较(我们毕竟比较id_a
)。所以Python丢弃了它。接下来,我们正在呼叫id(out_user)
。这为我们提供了一个int对象(b
),也为值139859764807552
。由于a
不再存在,b
可以在a
的位置,以相同的ID结尾。因此,我们在id()
上调用b
并返回一个整数对象id_b
。由于b
与a
处于同一记忆位置,并且由于ID基于记忆位置,因此id_a
等于id_b
(并再次id_a is id_b
为不是这样的。)
答案 2 :(得分:0)
我认为当你提取引用时,python会选择一个地址名称并在使用它时将其抛出并在你尝试再次提取时选择另一个。 检查here
In [71]: a = b = []
In [72]: a is b
Out[72]: True
In [73]: id(a) == id(b)
Out[73]: True
In [74]: id(a) - id(b)
Out[74]: 0
In [75]: id(a) is id(b)
Out[75]: False
In [76]: id(id(a)), id(id(b))
Out[76]: (45539872, 45539872)
In [77]: id(id(a))#--
Out[77]: 45540016 !
! see here its picking another reference then it pick before
In [78]: id(id(b))#--!
Out[78]: 45539896
In [81]: id(id(a)), id(id(b)) # but here it's again same
Out[81]: (45539824, 45539824)
In [82]: id(id(a)) == id(id(b))
Out[82]: True
In [83]: id(a) is id(b)
Out[83]: False