1

可能重复:
Python“is”运算符对整数的行为异常
为什么(0-6)为-6 = False?

因此,在玩了一下id(python 2.6.5)时,我注意到了以下内容(shell session):

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

当然,一旦我修改其中一个变量,它就会被分配给一个新的内存地址,即

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

最初将具有相同值的两个变量分配到相同的内存位置或只是优化即 CPython 是正常行为吗?

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

4

4 回答 4

3

正如glglgl 所提到的,这是 CPython 的一个实现细节。如果您查看Objects/longobject.cCPython 的源代码(例如 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 = 1a 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),. 这意味着-5256(包括)之间的数字通过small_ints数组 in共享Objects/longobject.c

-edit- 我看到elssar 注意到对于一些文字的实习有类似的答案。如this answer所述,文档中PyInt_FromLong也提到了这一事实。

于 2012-12-20T17:00:44.063 回答
2
  1. 在 python 中,所有变量都是指向某些对象的指针。偶数。
  2. 数字是不可变的对象。因此,CPython 不需要创建具有相同值的新对象。
  3. 这并不意味着 CPython 将始终使用相同的对象。
  4. 在您的第一个示例中,变量ab指向同一个对象。
  5. 当你让b += 1你“创建”新对象时2
于 2012-12-20T15:52:09.343 回答
2

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

如果这样做a = b = 1,两者ab都绑定到表示 的同一个对象1

如果你这样做a = 1; b = 1,我认为它是相同的 CPython 细节。一般来说,一个实现可以选择让两个对象在1这里都表示和使用它们。但由于这会浪费内存,因此通常不会以这种方式完成。

于 2012-12-20T15:53:26.027 回答
1

a并且b两者都使用 ID 引用内存 ( 1)中的同一个对象140524904。一旦你b += 1有了2,它位于其他地方。

于 2012-12-20T15:51:55.890 回答