2011-05-23 98 views
22

我最近在擺弄id,並意識到(c?)Python做了一些非常合理的事情:它確保小的整數始終具有相同的idpython添加小整數時幕後會發生什麼?

>>> a, b, c, d, e = 1, 2, 3, 4, 5 
>>> f, g, h, i, j = 1, 2, 3, 4, 5 
>>> [id(x) == id(y) for x, y in zip([a, b, c, d, e], [f, g, h, i, j])] 
[True, True, True, True, True] 

但是,後來我想到了數學運算的結果是否也是如此。原來它是:

>>> nines = [(x + y, 9) for x, y in enumerate(reversed(range(10)))] 
>>> [id(x) == id(y) for x, y in nines] 
[True, True, True, True, True, True, True, True, True, True] 

好像它開始在n = 257失敗...

>>> a, b = 200 + 56, 256 
>>> id(a) == id(b) 
True 
>>> a, b = 200 + 57, 257 
>>> id(a) == id(b) 
False 

但有時還是甚至更大的數字作品:

>>> [id(2 * x + y) == id(300 + x) for x, y in enumerate(reversed(range(301)))][:10] 
[True, True, True, True, True, True, True, True, True, True] 

這是怎麼回事在這? python如何做到這一點?

回答

17

Python保留一定數量的int對象池。當您在該範圍內創建一個時,您實際上會獲得對原有範圍的引用。我懷疑這是出於優化原因。

對於超出該池範圍的數字,每當嘗試創建一個時,您似乎都會收回一個新對象。

$ python 
Python 3.2 (r32:88445, Apr 15 2011, 11:09:05) 
[GCC 4.5.2 20110127 (prerelease)] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> x = 300 
>>> id(x) 
140570345270544 
>>> id(100+200) 
140570372179568 
>>> id(x*2) 
140570345270512 
>>> id(600) 
140570345270576 

Source

的PyObject * PyInt_FromLong(長IVAL) 返回值:新基準。創建一個 新的整數對象,其值爲 ival。

當前實現持續的 整數數組對象爲-5和256之間的所有 整數,當你 創建在該範圍內的int你 其實只是回到 現有對象的引用。所以應該是 可能改變1的值。我 懷疑Python的行爲 這種情況是未定義的。 :-)

重點煤礦

+0

數字越大,會發生什麼?有時候ID仍然是一樣的。它正在做一個哈希查找什麼的? – jsau 2011-05-23 18:46:56

+0

@jsau:我編輯了我的答案以包含該內容。 – Daenyth 2011-05-23 18:50:24

+0

@Daenyth,是的,但有時它不是一個新對象;如我的例子所示,有時'2 * x + y'返回與'300 + x'相同的對象。或者我誤解了什麼'ID'呢? – jsau 2011-05-23 18:55:24

2

AFAIK,id與參數的大小無關。它必須返回一個終生唯一標識符,並且它可以爲兩個不同的參數返回相同的結果,如果它們不同時存在的話。

+0

從文檔:返回對象的「身份」。這是一個整數(或長整數),在整個生命週期中保證這個對象是唯一的並且是常量。具有非重疊生命週期的兩個對象可能具有相同的id()值。 – Hyperboreus 2011-05-23 18:44:20

+0

@Daenyth:請指出不正確的地方。呃,爲什麼你刪除你的評論而不是解釋它? – Hyperboreus 2011-05-23 18:45:38

+0

根據Daenyth的回答,似乎它與參數的大小有關,如果大小是指數值的大小。 – jsau 2011-05-23 18:49:11

18

你已經陷入了不常見陷阱:

id(2 * x + y) == id(300 + x) 

兩個表達式2 * x + y300 + x沒有重疊的壽命。這意味着Python可以計算左手邊,取其id,然後在計算右手邊之前釋放該整數。當CPython釋放一個整數時,它將它放在一個已釋放整數列表中,然後在下一次需要它時重新使用它。因此,即使計算結果非常不同,您的ID匹配:

>>> x, y = 100, 40000 
>>> id(2 * x + y) == id(300 + x) 
True 
>>> 2 * x + y, 300 + x 
(40200, 400) 
+1

Ahhhhhh。好的,這是有道理的。謝謝! – jsau 2011-05-23 19:05:38

+0

所以,如果你上面說的是字面上的真實的話,那麼就有一種感覺,python ints _are_ mutable(只有在被垃圾收集之後)。 – jsau 2011-05-23 19:23:31

相關問題