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