Files
ailearning/docs/da/019.md
2020-10-19 21:08:55 +08:00

386 lines
4.8 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```