我正在使用repl.it
用于python3 -
这是我做的一系列作业
x34=20
x34
=> 20
hex(id(x34))
=> '0x7fdb5d318960'
x34=30
hex(id(x34))
=> '0x7fdb5d318aa0'
hex(id(x34))
=> '0x7fdb5d318aa0'
x34
=> 30
hex(id(x34))
=> '0x7fdb5d318aa0'
x34=20
hex(id(x34))
=> '0x7fdb5d318960'
为什么变量x34
的地址在重新分配值30
时会发生变化?
答案 0 :(得分:3)
你的根本误解是 id属于Python对象,而不是变量。因此,任何重新分配给新对象会导致ID更改:
>>> x = (1,2)
>>> hex(id(x))
'0x107526e48'
>>> x = (2, 4)
>>> hex(id(x))
'0x107526e88'
注意,每次创建新对象时都会发生这种情况:
>>> x = (1, 2)
>>> hex(id(x))
'0x107526e48'
>>> x = (1, 2)
>>> hex(id(x))
'0x107526d48'
>>> x = (1, 2)
>>> hex(id(x))
'0x107526dc8'
不可变性或缺乏与之无关。注意,tuple
个对象是不可变的。但是,有一个small int
s are cached的CPython实现细节。这就是您会看到以下行为的原因:
>>> x = 10
>>> hex(id(x))
'0x10714d920'
>>> x = 10
>>> hex(id(x))
'0x10714d920'
>>> x = 10
>>> hex(id(x))
'0x10714d920'
基本上,在CPython中,-5到256之间的int
个对象是单例。就像None
:
>>> x = None
>>> id(x)
4413491112
>>> x = None
>>> id(x)
4413491112
但是,对于大型int
s,这种方法不会像在tuple
s一样工作:
>>> x = 888
>>> hex(id(x))
'0x107550070'
>>> x = 888
>>> hex(id(x))
'0x10736aef0'
>>> x = 888
>>> hex(id(x))
'0x107550030'
但要小心,因为id
仅保证对象的生命周期是唯一的。所以,有时候,你会看到从堆中返回相同的内存,因为Python解释器试图对内存有效:
>>> x = 888
>>> hex(id(x))
'0x107550050'
>>> x = 888
>>> hex(id(x))
'0x10736aef0'
>>> x = 888
>>> hex(id(x))
'0x107550090'
>>> x = 888
>>> hex(id(x))
'0x10736aef0'
>>> x = 888
>>> hex(id(x))
'0x107550070'
同样,任何对象可能会发生这种情况:
>>> x = object()
>>> hex(id(x))
'0x1072db120'
>>> x = object()
>>> hex(id(x))
'0x1072db110'
>>> x = object()
>>> hex(id(x))
'0x1072db120'
对象的价值并不重要,
>>> x = 888
>>> hex(id(x))
'0x107549fd0'
>>> x = 999
>>> hex(id(x))
'0x107550090'
>>> x = 777
>>> hex(id(x))
'0x107549fd0'
实际上,类型也不一定都是重要的:
>>> class A:
... pass
...
>>> class B:
... pass
...
>>> class C:
... pass
...
>>> for i in range(12):
... if i%3 == 1:
... print(A())
... elif i%3 == 2:
... print(B())
... else:
... print(C())
...
<__main__.C object at 0x107535a58>
<__main__.A object at 0x107535a58>
<__main__.B object at 0x107535a58>
<__main__.C object at 0x107535a58>
<__main__.A object at 0x107535a58>
<__main__.B object at 0x107535a58>
<__main__.C object at 0x107535a58>
<__main__.A object at 0x107535a58>
<__main__.B object at 0x107535a58>
<__main__.C object at 0x107535a58>
<__main__.A object at 0x107535a58>
<__main__.B object at 0x107535a58>
这完全取决于口译员的实施。
但是,如果您保留对对象的另一个引用,原始文件将不会在重新分配期间死亡, 保证:
>>> hex(id(x))
'0x1072db140'
>>> y = x
>>> hex(id(y)) # guaranteed to be the same as x
'0x1072db140'
>>> x = object()
>>> hex(id(x)) # guaranteed to be new
'0x1072db130'
答案 1 :(得分:2)
基本上,您对每个作业执行的操作是创建类型为int
的新对象,取消引用较旧的对象(20 in this case
),并引用变量(x34
)到新的(30
)。
还是要小心,因为实现可能很棘手,看看这个:
>>> x34=20
>>> x34
20
>>> hex(id(x34))
'0x107d67f70'
>>> x34=30
>>> x34
30
>>> hex(id(x34))
'0x107d680b0'
>>> x35=30
>>> hex(id(x35))
'0x107d680b0'
正如您所看到的,两个不同的变量(x34
和x35
)指向同一个对象(在这种情况下为30
),当它们理论上为#34;不该&#39;吨
因为两个30
是不同的对象,即使它们具有相同的值。
Python解释器非常聪明,可以意识到30
是一个不可变对象,所以它避免浪费内存创建两个30
只有一个就足够了因为它(解释器)永远不会修改(由于不变性规则)一个对象和这样的修改反映在指向同一对象的另一个变量中。
答案 2 :(得分:0)
python中的数字是不可变对象,这意味着它可以轻松地创建对同一对象的新引用。可变对象在创建后可以更改,而不可变对象则不能。
>>> id(1)
94292933210472
>>>
>>> id(2)
94292933210448
>>>
>>> a = 1
>>> id(a)
94292933210472
>>>
>>> a = a +1
>>> id(a)
94292933210448
正如您所见,当您尝试分配
时,Python no 1和2具有不同的IDa = 1
然后 a 名称引用1的id或整数1对象具有标记为“a”的标记。当你尝试分配
时a = 2
或 a = a + 1
然后 a 名称引用2的id或整数2对象有一个标记为“a”的标记。
或尝试时
b = a
“b”是与“a”绑定到同一对象的anothor标记。
一个很好的解释是 Here
和差异