在学习对象的可变性时,我在我的python shell中玩了一下。
我发现了一些奇怪的事情:
>>> x=5.0
>>> id(x)
48840312
>>> id(5.0)
48840296
>>> x=x+3.0
>>> id(x) # why did x (now 8.0) keep the same id as 5.0?
48840296
>>> id(5.0)
36582128
>>> id(5.0)
48840344
为什么在语句x=x+3.0
之后重用5.0的id?
答案 0 :(得分:2)
从根本上说,问题的答案是“在数字上调用id()
会给你带来不可预测的结果”。之所以这样是因为与Java这样的语言不同,其中原语在字面上是它们在内存中的价值,Python中的“原语”仍然是对象,并且不能保证每次都使用完全相同的对象,仅仅是功能相同的一个人会。
CPython将整数的值从-5缓存到256以提高效率(确保对id()
的调用始终相同),因为这些是常用的并且可以有效地缓存,但是语言没有任何关系要求是这种情况,其他实现可能选择不这样做。
每当你在Python中编写双文字时,你都要求解释器将字符串转换为有效的数字对象。如果可以,Python将重用现有对象,但如果它不能轻易确定对象是否已经退出,那么它只会创建一个新对象。
这并不是说Python中的数字是可变的 - 它们不是。用户在创建后无法更改Python中任何数字实例,例如5.0
。但是,就解释器而言,构建多个相同数字的实例并没有错。
表示x = 5.0
的对象的特定示例被重用于x += 3.0
的值是一个实现细节。在封面下,如果认为合适,CPython可以重用数字对象,包括整数和浮点数,以避免构造一个全新对象的昂贵活动。但我强调,这是一个实现细节;完全可能某些情况下不会显示此行为,CPython可以随时将其数字处理逻辑更改为不再采用这种方式。你应该避免编写任何依赖于这个怪癖的代码。
正如eryksun指出的那样,另一种选择就是你偶然发现了一个被垃圾收集并在同一位置被替换的对象。从用户的角度来看,两种情况之间没有区别,这有助于强调id()
不应该用于“原语”。
答案 1 :(得分:0)
魔鬼在details
PyObject * PyInt_FromLong(long ival)
Return value: New reference. Create a new integer object with a value of ival.
当您在该范围内创建int时,当前实现为-5到256之间的所有整数保留一个整数对象数组 实际上,您只需返回对现有对象的引用。所以 应该可以改变1的值。我怀疑这种行为 在这种情况下,Python是未定义的。 : - )
注意这仅适用于CPython,可能不适用于其他Python发布。