{ "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 }