{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 属性" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 只读属性" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "只读属性,顾名思义,指的是只可读不可写的属性,之前我们定义的属性都是可读可写的,对于只读属性,我们需要使用 `@property` 修饰符来得到:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Leaf(object):\n", " def __init__(self, mass_mg):\n", " self.mass_mg = mass_mg\n", " \n", " # 这样 mass_oz 就变成属性了\n", " @property\n", " def mass_oz(self):\n", " return self.mass_mg * 3.53e-5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这里 `mass_oz` 就是一个只读不写的属性(注意是属性不是方法),而 `mass_mg` 是可读写的属性:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.00706\n" ] } ], "source": [ "leaf = Leaf(200)\n", "\n", "print leaf.mass_oz" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "可以修改 `mass_mg` 属性来改变 `mass_oz`:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.005295\n" ] } ], "source": [ "leaf.mass_mg = 150\n", "\n", "print leaf.mass_oz" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "是属性不是方法:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "ename": "TypeError", "evalue": "'float' object is not callable", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mleaf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmass_oz\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: 'float' object is not callable" ] } ], "source": [ "leaf.mass_oz()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "而且是只读属性,不可写:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "ename": "AttributeError", "evalue": "can't set attribute", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mleaf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmass_oz\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m0.001\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m: can't set attribute" ] } ], "source": [ "leaf.mass_oz = 0.001" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "回到 `forest` 的例子,我们希望加入几个只读属性:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import numpy as np\n", "\n", "class Forest(object):\n", " \"\"\" Forest can grow trees which eventually die.\"\"\"\n", " def __init__(self, size=(150,150)):\n", " self.size = size\n", " self.trees = np.zeros(self.size, dtype=bool)\n", " self.fires = np.zeros((self.size), dtype=bool)\n", " \n", " def __repr__(self):\n", " my_repr = \"{}(size={})\".format(self.__class__.__name__, self.size)\n", " return my_repr\n", " \n", " def __str__(self):\n", " return self.__class__.__name__\n", " \n", " @property\n", " def num_cells(self):\n", " \"\"\"Number of cells available for growing trees\"\"\"\n", " return np.prod(self.size)\n", " \n", " @property\n", " def tree_fraction(self):\n", " \"\"\"\n", " Fraction of trees\n", " \"\"\"\n", " num_trees = self.trees.sum()\n", " return float(num_trees) / self.num_cells\n", " \n", " @property\n", " def fire_fraction(self):\n", " \"\"\"\n", " Fraction of fires\n", " \"\"\"\n", " num_fires = self.fires.sum()\n", " return float(num_fires) / self.num_cells" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "查看属性:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "22500" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "forest = Forest()\n", "\n", "forest.num_cells" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "生成一个较小的森林:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "100" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "small_forest = Forest((10, 10))\n", "small_forest.num_cells" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "初始状态下,树和火灾的比例都是 0:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "small_forest.tree_fraction" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "small_forest.fire_fraction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 可读写的属性" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "对于 `@property` 生成的只读属性,我们可以使用相应的 `@attr.setter` 修饰符来使得这个属性变成可写的:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Leaf(object):\n", " def __init__(self, mass_mg):\n", " self.mass_mg = mass_mg\n", " \n", " # 这样 mass_oz 就变成属性了\n", " @property\n", " def mass_oz(self):\n", " return self.mass_mg * 3.53e-5\n", " \n", " # 使用 mass_oz.setter 修饰符\n", " @mass_oz.setter\n", " def mass_oz(self, m_oz):\n", " self.mass_mg = m_oz / 3.53e-5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "测试:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.00706\n", "0.005295\n" ] } ], "source": [ "leaf = Leaf(200)\n", "print leaf.mass_oz\n", "\n", "leaf.mass_mg = 150\n", "print leaf.mass_oz" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "修改 `mass_oz` 属性:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "283.28611898\n" ] } ], "source": [ "leaf.mass_oz = 0.01\n", "print leaf.mass_mg" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "一个等价的替代如下:\n", "\n", "```python\n", "class Leaf(object):\n", " def __init__(self, mass_mg):\n", " self.mass_mg = mass_mg\n", " \n", " def get_mass_oz(self):\n", " return self.mass_mg * 3.53e-5\n", " \n", " def set_mass_oz(self, m_oz):\n", " self.mass_mg = m_oz / 3.53e-5\n", " \n", " mass_oz = property(get_mass_oz, set_mass_oz)\n", "```" ] } ], "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 }