[英]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.