2012-12-20 25 views
1

可能重复:
Python “is” operator behaves unexpectedly with integers
Why (0-6) is -6 = False?Python变量分配和`id`关键字

所以,虽然带着几分玩id(蟒蛇2.6.5),我注意到以下(shell会话):

>>> a = 1 
>>> id(a) 
140524904 
>>> b = 1 
>>> id(b) 
140524904 

当然,只要我修改它被分配到一个新的内存地址的一个变量,即

>>> b += 1 
>>> id(b) 
140524892 

难道是正常的行为最初分配具有相同价值观相同的内存位置两个变量或只是一个优化即CPython?

P.s.我花了一点时间浏览parser中的代码,但无法找到变量分配的位置和方式。

+1

请参阅http://stackoverflow.com/questions/306313/python-is-operator-behaves-unexpectedly-with-integers –

+0

谢谢你们两位,我会将其标记为重复 – nvlass

+1

回答

4

作为mentioned by glglgl,这是CPython的实现细节。如果您在CPython的源代码(例如版本3.3.0)看Objects/longobject.c,你会发生的事情找到答案:

#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 bTrue,即使你说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)。这意味着-5256(含)之间的数字通过Objects/longobject.c中的small_ints数组共享。

-edit-我看到elssar noted有一个similar answer about interning of some literals。这个事实也被提及in the documentation for PyInt_FromLong,如this answer所述。

+0

非常感谢您的详尽解答(也适用于python源代码中的指针 - 发现此问题需要一段时间)!并感谢所有其他有用的答案和评论! – nvlass

+0

我花了一段时间找到它的唯一原因是因为我正在寻找名称中带有'int'的东西。但是一旦你找到这个源文件,它几乎是第一件事。这可能是因为,我引用,“/ * XXX该文件的功能组织很糟糕* /'”;) – 2012-12-20 18:20:24

1

ab都指内存中的同一对象(1),ID为140524904。一旦你做了b += 1你有2,它位于其他地方。

+0

a = 1000和b = 1000? –

2
  1. 在Python中的所有变量都指向某些对象。偶数。
  2. 数字是不可变的对象。因此,CPython不需要创建具有相同值的新对象。
  3. 这并不意味着CPython将始终使用相同的对象。
  4. 在你的第一个例子中,变量ab指向同一个对象。
  5. 当您制作b += 1时,您“创建”了新对象2
+0

+1我知道元组和字符串是不可变的,但从来没有想到数字太多(或者我可能错过了那个)。 – nvlass

2

这里的术语“变量”必须精确:一方面是对象,另一方面是绑定到对象的名称。

如果你这样做a = b = 1ab绑定到相同的对象代表1

如果你做a = 1; b = 1,我认为这是CPython的细节,它是相同的。一般来说,一个实现可以选择两个对象都代表1并在这里使用它们。但因为这会浪费记忆,所以通常不这样做。

相关问题