[英]Python , variable store in memory
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])不同?
当CPython REPL执行一行时,它将:
可以通过dis
模块检查编译结果:
>>> 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
没有规则或保证说明id(a [0])应该等于id(a [1]),因此问题本身是没有根据的。 您应该问的问题是为什么id(a[0])
和id(a[1])
实际上相同。
如果在a.append(1234)
之后加上id(a[2])
,则可能会或可能不会获得相同的ID。 正如@hiro protagonist
指出的那样,这些只是内部优化,您不应依赖这些优化。
Python列表与C数组非常不同。
AC阵列只是一块连续的内存,因此,根据定义,其第一个(第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的int
对象的引用 。因此, id(x[0])
是该对象的“指针”。
用C术语来说,数组的元素可以看作是指向存储在其中的对象的指针,而不是对象本身的指针。
由于没有必要让两个对象代表相同的数字1,因此在Python解释器运行期间id(1)
始终相同。 插图:
x = [1, 2, 3]
y = [1, 100, 1000]
assert id(x) != id(y) # obviously
assert id(x[0]) == id(y[0]) == id(1) # yes, the same int object
CPython实际上为一些最常用的小数字预分配了对象( 请参阅此处的注释 )。 对于较大的数字,事实并非如此,这可能导致两个较大的“副本”具有不同的id()
值 。
您必须注意:id()实际上给出变量或文字值的id。 对于程序中使用的每个文字/值(即使在id()本身内),id()都会返回(试图返回)程序生命周期内文字/变量的唯一标识符。 可用于:
对于您的情况,即使a [0]和a [1]的值可以相同,也无法保证。 它取决于在python程序生命周期中由内部处理的文字/变量的创建顺序/时间顺序。
情况1:
Type "help", "copyright", "credits" or "license" for more information.
>>> a=[1234,1234]
>>> id(a[0])
52687424
>>> id(a[1])
52687424
情况2(请注意,在情况末尾,a [0]和a [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
>>>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.