首先创建一个用于显示引用计数的函数(请注意,每次函数都必须为-1以获取正确的值,因为该函数本身将INCREF-s作为参数)

>>> from sys import getrefcount as rc
>>> x=1.1
>>> rc(x)-1
1


现在再次引用相同的PyObject

>>> y=x

>>> rc(x)-1
2
>>> rc(y)-1
2

>>> x is y
True


现在在第二个句柄y上执行操作:

>>> y+=1


这应该在PyNumber_InPlaceAdd指向的PyObject上调用y

因此,如果这是真的,我希望x也能读2.1

>>> x,y
(1.1, 2.1)

>>> x is y
False

>>> rc(x)-1
1
>>> rc(y)-1
1


所以我的问题是,Python在内部做什么以提供正确的行为,而不是我从查看PyNumber_InPlaceAdd所期望的行为?

(注意:我使用的是1.1;如果使用的是1,则初始引用计数将为> 300,因为1必须在CPython的幕后所有位置使用,并且足够聪明重用对象。)

(这也引出了一个问题:如果我有foo = 20; bar = 19; bar += 1,这是否意味着它必须浏览其所有对象并检查是否已经存在具有该值的对象,如果可以的话,请重用它?一个简单的测试表明答案是不,这是个好消息。一旦程序变大,它就会变得非常慢。因此Python必须仅对小整数进行优化。)

最佳答案

为此,您不需要getrefcount,只需使用id

>>> x = 1.1
>>> id(x)
50107888
>>> y = x
>>> id(y)
50107888 # same object
>>> y += 1
>>> id(y)
40186896 # different object
>>> id(x)
50107888 # no change there


float对象(以及strint)在Python中是不可变的,它们不能就地更改。因此,加法操作将使用新值创建一个新对象,并将其有效地分配给名称y

temp = y + 1
y = temp




在CPython中,从-5256的整数是“ interned”的,即被存储以供重用,这样任何带有结果的操作例如1将引用相同的对象。与每次需要这些频繁使用的值创建新对象相比,这节省了内存。没错,每次可能需要一个新对象时,都要搜索所有现有对象以查找匹配项是很痛苦的,因此只能在有限的范围内完成。使用连续范围还意味着“搜索”实际上只是数组中的偏移量。

关于python - 在Python中,为什么不'y = x; y + = 1'也增加x?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27399340/

10-10 19:10