mirror of
https://github.com/apachecn/ailearning.git
synced 2026-02-09 13:25:39 +08:00
386 lines
4.8 KiB
Markdown
386 lines
4.8 KiB
Markdown
# 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
|
||
|
||
``` |