可能重复:
Python “is” operator behaves unexpectedly with integers
Why (0-6) is -6 = False?
所以,在使用id
(python 2.6.5)时,我注意到以下内容(shell会话):
>>> a = 1
>>> id(a)
140524904
>>> b = 1
>>> id(b)
140524904
当然,只要修改其中一个变量,就会将其分配给新的内存地址,即
>>> b += 1
>>> id(b)
140524892
最初将具有相同值的变量分配给相同的内存位置或仅仅是CPython的优化是正常的行为吗?
P.S。我花了一点时间浏览parser
中的代码,但找不到变量的分配位置和方式。
答案 0 :(得分:3)
作为mentioned by glglgl,这是CPython的实现细节。如果您在CPython的源代码中查看Objects/longobject.c
(例如版本3.3.0),您将找到正在发生的事情的答案:
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
/* Small integers are preallocated in this array so that they
can be shared.
The integers that are preallocated are those in the range
-NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
这解释了为什么在a = 1; b = 1
之后,a is b
将True
,即使您说a += 2; b +=2; a -= 2; b -= 2
。只要计算出一个数字,使其具有适合此数组的值,就可以从该数组中选择生成的对象,从而节省一点内存。
您可以使用如下函数计算出此small_ints
数组的范围:
def binary_search(predicate, lo, hi):
while lo + 1 < hi:
mid = (lo + hi) / 2
if predicate(mid):
lo = mid
else:
hi = mid
return lo
def is_small_int(n):
p = n + 1
q = n + 1
return (p - 1) is (q - 1)
def min_neg_small_int():
p, q = -1, -1
if p is not q:
return 0
while p is q:
p += p
q += q
return binary_search(is_small_int, p / 2, p) - 1
def max_pos_small_int():
p, q = 1, 1
if p is not q:
return 0
while p is q:
p += p
q += q
return binary_search(is_small_int, p / 2, p)
def small_int_bounds():
return (min_neg_small_int(), max_pos_small_int())
对于我的构建(Python 2.7,64位Windows构建),small_int_bounds() == (-5, 256)
。这意味着-5
和256
(包括)之间的数字通过small_ints
中的Objects/longobject.c
数组共享。
-edit-我看到elssar noted有一个similar answer about interning of some literals。正如in the documentation for PyInt_FromLong
所述,this answer也提到了这一事实。
答案 1 :(得分:2)
a
和b
指向同一个对象。b += 1
时,您“创建”新对象2
。答案 2 :(得分:2)
这里的术语&#34;变量&#34;必须精确:一方面有对象,另一方面有绑定对象的名称。
如果您执行a = b = 1
,则a
和b
都绑定到代表1
的同一对象。
如果你做a = 1; b = 1
,我认为这是一个CPython细节,它是相同的。通常,实现可以选择两个对象都表示1
并在此处使用它们。但由于这会浪费内存,通常不会以这种方式完成。
答案 3 :(得分:1)
a
和b
都引用内存中的同一对象(1
),ID为140524904
。完成b += 1
后,您有2
,位于其他地方。