为变量分配不同的值时,为什么变量的地址在python中会发生变化?

时间:2017-08-28 04:00:17

标签: python

我正在使用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时会发生变化?

3 个答案:

答案 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 ints 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'

正如您所看到的,两个不同的变量(x34x35)指向同一个对象(在这种情况下为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具有不同的ID
a = 1 

然后 a 名称引用1的id或整数1对象具有标记为“a”的标记。当你尝试分配

a = 2

或     a = a + 1

然后 a 名称引用2的id或整数2对象有一个标记为“a”的标记。

或尝试时

b = a

“b”是与“a”绑定到同一对象的anothor标记。

一个很好的解释是 Here

和差异

<强> immutable vs mutable in python