a=[1234,1234] #list
a
[1234, 1234]
id(a[0])
38032480
id(a[1])
38032480
b=1234 #b is a variable of integer type
id(b)
38032384
为什么id(b)与python中的id(a [0])和id(a [1])不同?
答案 0 :(得分:2)
当CPython REPL执行一行时,它将:
可以通过dis
module:
>>> dis.dis('a = [1234, 1234, 5678, 90123, 5678, 4321]')
1 0 LOAD_CONST 0 (1234)
2 LOAD_CONST 0 (1234)
4 LOAD_CONST 1 (5678)
6 LOAD_CONST 2 (90123)
8 LOAD_CONST 1 (5678)
10 LOAD_CONST 3 (4321)
12 BUILD_LIST 6
14 STORE_NAME 0 (a)
16 LOAD_CONST 4 (None)
18 RETURN_VALUE
请注意,所有1234都加载了" LOAD_CONST 0
",并且所有5678都加载了" LOAD_CONST 1
"。这些引用与代码对象关联的常量表。此处的表格为(1234, 5678, 90123, 4321, None)
。
编译器知道代码对象中1234的所有副本都是相同的,因此只会为所有副本分配一个对象。
因此,正如OP观察到的那样,a[0]
和a[1]
确实引用了同一个对象:来自该行代码的代码对象的常量表的相同常量。
执行b = 1234
时,将再次编译并执行,与前一行无关,因此将分配不同的对象。
(您可以阅读http://akaptur.com/blog/categories/python-internals/以获得有关如何解释代码对象的简要介绍)
在REPL之外,当你执行*.py
文件时,每个函数都被编译成单独的代码对象,所以当我们运行时:
a = [1234, 1234]
b = 1234
print(id(a[0]), id(a[1]))
print(id(b))
a = (lambda: [1234, 1234])()
b = (lambda: 1234)()
print(id(a[0]), id(a[1]))
print(id(b))
我们可能会看到类似的内容:
4415536880 4415536880
4415536880
4415536912 4415536912
4415537104
a[0]
和a[1]
的地址为第一个lambda的4415536912。b
的地址为第二个lambda的4415537104。另请注意,此结果仅适用于CPython。其他实现在分配常量方面有不同的策略。例如,在PyPy中运行上面的代码给出了:
19745 19745
19745
19745 19745
19745
答案 1 :(得分:1)
没有规则或保证声明id(a [0])应该等于id(a [1]),所以问题本身没有实际意义。您应该问的问题是为什么id(a[0])
和id(a[1])
实际上是相同的
如果您a.append(1234)
后跟id(a[2])
,则可能会或可能不会获得相同的ID。正如@hiro protagonist
指出的那样,这些只是你不应该依赖的内部优化。
答案 2 :(得分:1)
Python列表与C数组非常不同。
C数组只是一个连续内存块,因此根据定义,其第一个(第0个)元素的地址是数组本身的地址。 C中的数组访问只是指针算术,而[]
符号只是指针算术的语法糖的一小部分。表达式int x[]
只是int * x
的另一种形式。
为了示例,我们假设在Python中,id(x)
是“X的内存地址”,因为*x
将在C中。(对于所有Python都不是这样)实现,甚至在CPython中都没有保证。它只是一个唯一的数字。)
在C中,int
只是与体系结构相关的字节数,因此对于int x = 1
,表达式*x
指向这些字节。
Python中的所有内容都是一个对象,包括数字。这就是为什么id(1)
引用类型int
描述数字1
的对象的原因。您可以调用其方法:(1).__str__()
将返回字符串'1'
。
因此,当您拥有x = [1, 2, 3]
时,id(x)
是具有三个元素的list
对象的“指针”。 list
对象本身非常复杂。但是x[0]
不是构成整数值1的字节;它内部是一个引用到{1}}对象的数字1.因此int
是该对象的“指针”。
在C语言中,数组的元素可以看作指向存储在其中的对象的指针,而不是对象本身。
由于没有必要让两个对象表示相同的数字1,因此id(x[0])
在Python解释器运行期间始终是相同的。举例说明:
id(1)
CPython实际上为一些最常用的小数字(see comments here)预分配对象。对于较大的数字,情况并非如此,can lead to two 'copies' of a larger number having different id()
values。
答案 3 :(得分:1)
你必须注意:id()实际上给出了变量或文字值的id。对于程序中使用的每个文字/值(即使在id()本身内),id()返回(尝试返回)程序生命周期中文字/变量的唯一标识符。这可以用于:
至于你的情况,即使两者的值都相同,也不能保证[0]和[1]会给出相同的id。它取决于在python程序生命周期中创建文字/变量的顺序/时间顺序,并由python内部处理。
案例1:
Type "help", "copyright", "credits" or "license" for more information.
>>> a=[1234,1234]
>>> id(a[0])
52687424
>>> id(a[1])
52687424
案例2(请注意,在案例结尾处,[0]和[1]具有相同的值但不同的ID):
Type "help", "copyright", "credits" or "license" for more information.
>>> a=[1,1234]
>>> id(1)
1776174736
>>> id(1234)
14611088
>>> id(a[0])
1776174736
>>> id(a[1])
14611008
>>> a[0]=1234
>>> id(1234)
14611104
>>> id(a[0])
14611152
>>> id(a[1])
14611008
>>>