# Python 赋值机制 先看一个例子: In [1]: ```py x = [1, 2, 3] y = x x[1] = 100 print y ``` ```py [1, 100, 3] ``` 改变变量`x`的值,变量`y`的值也随着改变,这与**Python**内部的赋值机制有关。 ## 简单类型 先来看这一段代码在**Python**中的执行过程。 ```py x = 500 y = x y = 'foo' ``` * `x = 500` **Python**分配了一个 `PyInt` 大小的内存 `pos1` 用来储存对象 `500` ,然后,Python在命名空间中让变量 `x` 指向了这一块内存,注意,整数是不可变类型,所以这块内存的内容是不可变的。 | 内存 | 命名空间 | | --- | --- | | `pos1 : PyInt(500)` (不可变) | `x : pos1` | * `y = x` **Python**并没有使用新的内存来储存变量 `y` 的值,而是在命名空间中,让变量 `y` 与变量 `x` 指向了同一块内存空间。 | 内存 | 命名空间 | | --- | --- | | `pos1 : PyInt(500)` (不可变) | `x : pos1` `y : pos1` | * `y = 'foo'` **Python**此时分配一个 `PyStr` 大小的内存 `pos2` 来储存对象 `foo` ,然后改变变量 `y` 所指的对象。 | 内存 | 命名空间 | | --- | --- | | `pos1 : PyInt(500)` (不可变) `pos2 : PyStr('foo')` (不可变) | `x : pos1` `y : pos2` | 对这一过程进行验证,可以使用 `id` 函数。 ```py id(x) ``` 返回变量 `x` 的内存地址。 In [2]: ```py x = 500 id(x) ``` Out[2]: ```py 48220272L ``` In [3]: ```py y = x id(y) ``` Out[3]: ```py 48220272L ``` 也可以使用 `is` 来判断是不是指向同一个事物: In [4]: ```py x is y ``` Out[4]: ```py True ``` 现在 `y` 指向另一块内存: In [5]: ```py y = 'foo' id(y) ``` Out[5]: ```py 39148320L ``` In [6]: ```py x is y ``` Out[6]: ```py False ``` **Python**会为每个出现的对象进行赋值,哪怕它们的值是一样的,例如: In [7]: ```py x = 500 id(x) ``` Out[7]: ```py 48220296L ``` In [8]: ```py y = 500 id(y) ``` Out[8]: ```py 48220224L ``` In [9]: ```py x is y ``` Out[9]: ```py False ``` 不过,为了提高内存利用效率,对于一些简单的对象,如一些数值较小的int对象,**Python**采用了重用对象内存的办法: In [10]: ```py x = 2 id(x) ``` Out[10]: ```py 6579504L ``` In [11]: ```py y = 2 id(y) ``` Out[11]: ```py 6579504L ``` In [12]: ```py x is y ``` Out[12]: ```py True ``` ## 容器类型 现在来看另一段代码: ```py x = [500, 501, 502] y = x y[1] = 600 y = [700, 800] ``` * `x = [500, 501, 502]` Python为3个PyInt分配内存 `pos1` , `pos2` , `pos3` (不可变),然后为列表分配一段内存 `pos4` ,它包含3个位置,分别指向这3个内存,最后再让变量 `x` 指向这个列表。 | 内存 | 命名空间 | | --- | --- | | `pos1 : PyInt(500)` (不可变) `pos2 : PyInt(501)` (不可变) `pos3 : PyInt(502)` (不可变) `pos4 : PyList(pos1, pos2, pos3)` (可变) | `x : pos4` | * `y = x` 并没有创建新的对象,只需要将 `y` 指向 `pos4` 即可。 | 内存 | 命名空间 | | --- | --- | | `pos1 : PyInt(500)` (不可变) `pos2 : PyInt(501)` (不可变) `pos3 : PyInt(502)` (不可变) `pos4 : PyList(pos1, pos2, pos3)` (可变) | `x : pos4` `y : pos4` | * `y[1] = 600` 原来 `y[1]` 这个位置指向的是 `pos2` ,由于不能修改 `pos2` 的值,所以首先为 `600` 分配新内存 `pos5` 。 再把 `y[1]` 指向的位置修改为 `pos5` 。此时,由于 `pos2` 位置的对象已经没有用了,**Python**会自动调用垃圾处理机制将它回收。 | 内存 | 命名空间 | | --- | --- | | `pos1 : PyInt(500)` (不可变) `pos2 :` 垃圾回收 `pos3 : PyInt(502)` (不可变) `pos4 : PyList(pos1, pos5, pos3)` (可变) `pos5 : PyInt(600)` (不可变) | `x : pos4` `y : pos4` | * `y = [700, 800]` 首先创建这个列表,然后将变量 `y` 指向它。 | 内存 | 命名空间 | | --- | --- | | `pos1 : PyInt(500)` (不可变) `pos3 : PyInt(502)` (不可变) `pos4 : PyList(pos1, pos5, pos3)` (可变) `pos5 : PyInt(600)` (不可变) `pos6 : PyInt(700)` (不可变) `pos7 : PyInt(800)` (不可变) `pos8 : PyList(pos6, pos7)` (可变) | `x : pos4` `y : pos8` | 对这一过程进行验证: In [13]: ```py x = [500, 501, 502] print id(x[0]) print id(x[1]) print id(x[2]) print id(x) ``` ```py 48220224 48220248 48220200 54993032 ``` 赋值,`id(y)` 与 `id(x)` 相同。 In [14]: ```py y = x print id(y) ``` ```py 54993032 ``` In [15]: ```py x is y ``` Out[15]: ```py True ``` 修改 `y[1]` ,`id(y)` 并不改变。 In [16]: ```py y[1] = 600 print id(y) ``` ```py 54993032 ``` `id(x[1])` 和 `id(y[1])` 的值改变了。 In [17]: ```py print id(x[1]) print id(y[1]) ``` ```py 48220272 48220272 ``` 更改 `y` 的值,`id(y)` 的值改变 In [18]: ```py y = [700, 800] print id(y) print id(x) ``` ```py 54995272 54993032 ```