{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# python面向对象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "面向对象编程——Object Oriented Programming，简称OOP，是一种程序设计思想。OOP把对象作为程序的基本单元，一个对象包含了数据和操作数据的函数。\n",
    "面向过程的程序设计把计算机程序视为一系列的命令集合，即一组函数的顺序执行。为了简化程序设计，面向过程把函数继续切分为子函数，即把大块函数通过切割成小块函数来降低系统的复杂度。\n",
    "\n",
    "而面向对象的程序设计把计算机程序视为一组对象的集合，而每个对象都可以接收其他对象发过来的消息，并处理这些消息，计算机程序的执行就是一系列消息在各个对象之间传递。\n",
    "\n",
    "在Python中，所有数据类型都可以视为对象，当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类（Class）的概念。\n",
    "我们以一个例子来说明面向过程和面向对象在程序流程上的不同之处。\n",
    "\n",
    "假设我们要处理学生的成绩表，为了表示一个学生的成绩，面向过程的程序可以用一个dict表示："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "std1 = { 'name': 'Michael', 'score': 98 }\n",
    "std2 = { 'name': 'Bob', 'score': 81 }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Michael: 98\n"
     ]
    }
   ],
   "source": [
    "#而处理学生成绩可以通过函数实现，比如打印学生的成绩：\n",
    "def print_score(std):\n",
    "    print('%s: %s' % (std['name'], std['score']))\n",
    "\n",
    "print_score(std1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果采用面向对象的程序设计思想，我们首选思考的不是程序的执行流程，<br/>\n",
    "而是Student这种数据类型应该被视为一个对象，这个对象拥有name和score这两个属性（Property）。<br/>\n",
    "如果要打印一个学生的成绩，首先必须创建出这个学生对应的对象，<br/>\n",
    "然后，给对象发一个print_score消息，让对象自己把自己的数据打印出来。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name, score):\n",
    "        self.name = name\n",
    "        self.score = score\n",
    "\n",
    "    def print_score(self):\n",
    "        print('%s: %s' % (self.name, self.score))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给对象发消息实际上就是调用对象对应的关联函数，我们称之为对象的方法（Method）。面向对象的程序写出来就像这样："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Bart Simpson: 59\n"
     ]
    }
   ],
   "source": [
    "bart = Student('Bart Simpson', 59)\n",
    "bart.print_score()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "面向对象的设计思想是从自然界中来的，因为在自然界中，类（Class）和实例（Instance）的概念是很自然的。\n",
    "Class是一种抽象概念，比如我们定义的Class——Student，是指学生这个概念，而实例（Instance）则是一个个具体的Student，\n",
    "比如，Bart Simpson和Lisa Simpson是两个具体的Student。所以，面向对象的设计思想是抽象出Class，根据Class创建Instance。\n",
    "面向对象的抽象程度又比函数要高，因为一个Class既包含数据，又包含操作数据的方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "# 类和实例\n",
    "面向对象最重要的概念就是类（Class）和实例（Instance），必须牢记类是抽象的模板，比如Student类，而实例是根据类创建出来的一个个具体的“对象”，每个对象都拥有相同的方法，但各自的数据可能不同。\n",
    "\n",
    "**仍以Student类为例，在Python中，定义类是通过class关键字：**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "class后面紧接着是类名，即Student，类名通常是大写开头的单词，紧接着是(object)，表示该类是从哪个类继承下来的，继承的概念我们后面再讲，通常，如果没有合适的继承类，就使用object类，这是所有类最终都会继承的类。\n",
    "\n",
    "定义好了Student类，就可以根据Student类创建出Student的实例，创建实例是通过类名+()实现的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class '__main__.Student'>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.Student at 0x7fea18081710>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(Student)\n",
    "bart = Student()\n",
    "bart"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.Student at 0x7fea180745f8>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tom = Student()\n",
    "tom"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到，变量bart指向的就是一个Student的实例，后面的0x21f126eef28是内存地址，每个object的地址都不一样，而Student本身则是一个类。\n",
    "\n",
    "pytho可以自由地给一个实例变量绑定属性，比如，给实例bart绑定一个name属性：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Bart Simpson'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.name = 'Bart Simpson'\n",
    "bart.name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "bart.sex='F'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'F'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.sex"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br/>由于类可以起到**模板**的作用，因此，可以在创建实例的时候，把一些我们认为必须绑定的属性强制填写进去。<br/>\n",
    "通过定义一个特殊的**\\_\\_init\\_\\_**方法，在创建实例的时候，就把name，score等属性绑上去："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    #注意：特殊方法“__init__”前后分别有两个下划线！！！ \n",
    "    def __init__(self, name, score):\n",
    "        self.name = name\n",
    "        self.score = score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意到__init__方法的第一个参数永远是self，表示创建的实例本身，因此，在__init__方法内部，就可以把各种属性绑定到self，因为self就指向创建的实例本身。\n",
    "\n",
    "有了__init__方法，在创建实例的时候，就不能传入空的参数了，必须传入与__init__方法匹配的参数，但self不需要传，Python解释器自己会把实例变量传进去："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Bart Simpson'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart = Student('Bart Simpson', 59)\n",
    "bart.name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "59"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "和普通的函数相比，在类中定义的函数只有一点不同，就是第一个参数永远是实例变量self，并且，调用时，不用传递该参数。除此之外，类的方法和普通函数没有什么区别，\n",
    "所以，你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **数据封装**\n",
    "面向对象编程的一个重要特点就是数据封装。在上面的Student类中，每个实例就拥有各自的name和score这些数据。\n",
    "我们可以通过函数来访问这些数据，比如打印一个学生的成绩："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Bart Simpson: 59\n"
     ]
    }
   ],
   "source": [
    "def print_score(std):\n",
    "     print('%s: %s' % (std.name, std.score))\n",
    "\n",
    "print_score(bart)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但是，既然Student实例本身就拥有这些数据，要访问这些数据，就没有必要从外面的函数去访问，可以直接在Student类的内部定义访问数据的函数，这样，就把“数据”给封装起来了。\n",
    "这些封装数据的函数是和Student类本身是关联起来的，我们称之为类的方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "\n",
    "    def __init__(self, name, score):\n",
    "        self.name = name\n",
    "        self.score = score\n",
    "\n",
    "    def print_score(self):\n",
    "        print('%s: %s' % (self.name, self.score))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "要定义一个方法，除了第一个参数是self外，其他和普通函数一样。要调用一个方法，\n",
    "<br/>只需要在实例变量上直接调用，除了self不用传递，其他参数正常传入："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "bart = Student('Bart Simpson', 59)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Bart Simpson: 59\n"
     ]
    }
   ],
   "source": [
    "bart.print_score()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这样一来，我们从外部看Student类，就只需要知道，创建实例需要给出name和score，而如何打印，都是在Student类的内部定义的，\n",
    "这些数据和逻辑被“封装”起来了，调用很容易，但却不用知道内部实现的细节。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "封装的另一个好处是可以给Student类增加新的方法，比如get_grade："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student():\n",
    "    def __init__(self, name, score):# 构造函数，初始化函数\n",
    "        self.name = name\n",
    "        self.score = score\n",
    "\n",
    "    def print_score(self):\n",
    "        print('%s: %s' % (self.name, self.score))\n",
    "        \n",
    "    def get_grade(self):\n",
    "        if self.score >= 90:\n",
    "            return 'A'\n",
    "        elif self.score >= 60:\n",
    "            return 'B'\n",
    "        else:\n",
    "            return 'C'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "bart = Student('Bart Simpson', 59)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'C'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.get_grade()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同样的，get_grade方法可以直接在实例变量上调用，不需要知道内部实现细节："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name, score):\n",
    "        self.name = name\n",
    "        self.score = score\n",
    "\n",
    "    def get_grade(self):\n",
    "        if self.score >= 90:\n",
    "            return 'A'\n",
    "        elif self.score >= 60:\n",
    "            return 'B'\n",
    "        else:\n",
    "            return 'C'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Lisa A\n",
      "Bart C\n"
     ]
    }
   ],
   "source": [
    "lisa = Student('Lisa', 99)\n",
    "bart = Student('Bart', 59)\n",
    "print(lisa.name, lisa.get_grade())\n",
    "print(bart.name, bart.get_grade())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "# 访问限制\n",
    "\n",
    "\n",
    "在Class内部，可以有属性和方法，而外部代码可以通过直接调用实例变量的方法来操作数据，这样，就隐藏了内部的复杂逻辑。\n",
    "\n",
    "但是，从前面Student类的定义来看，外部代码还是可以自由地修改一个实例的name、score属性："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "59"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart = Student('Bart Simpson', 59)\n",
    "bart.score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "99"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.score = 99\n",
    "bart.score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果要让内部属性不被外部访问，可以把属性的名称前加上**两个下划线__**，在Python中，实例的变量名如果以**__**开头，就变成了一个**私有变量（private），**\n",
    "只有内部可以访问，外部不能访问，所以，我们把Student类改一改："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name, score,sex):\n",
    "        self.__name = name\n",
    "        self.__score = score\n",
    "        self.sex = sex\n",
    "\n",
    "    def print_score(self):\n",
    "        print('%s: %s' % (self.__name, self.__score))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "改完后，对于外部代码来说，没什么变动，但是已经**无法从外部访问实例变量.\\_\\_name和实例变量.\\_\\_score了：**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'Student' object has no attribute '__name'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-17-ce01bc9ce481>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mbart\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mStudent\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Bart Simpson'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m59\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'M'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mbart\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'Student' object has no attribute '__name'"
     ]
    }
   ],
   "source": [
    "bart = Student('Bart Simpson', 59, 'M')\n",
    "bart.__name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这样就确保了外部代码不能随意修改对象内部的状态，这样通过访问限制的保护，代码更加健壮。\n",
    "\n",
    "但是如果**外部代码要获取name和score怎么办？**可以给Student类增加get_name和get_score这样的方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "\n",
    "    def get_name(self):\n",
    "        return self.__name\n",
    "\n",
    "    def get_score(self):\n",
    "        return self.__score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果又要允许外部代码修改score怎么办？可以再给Student类增加set_score方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name, score):\n",
    "        self.__name = name\n",
    "        self.__score = score\n",
    "\n",
    "    def set_score(self, score):\n",
    "        self.__score = score\n",
    "    def get_score(self):\n",
    "        print(self.__score)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "ss1 = Student('aa',80)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "80\n"
     ]
    }
   ],
   "source": [
    "ss1.get_score()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88\n"
     ]
    }
   ],
   "source": [
    "ss1.set_score(88)\n",
    "ss1.get_score()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你也许会问，原先那种直接通过bart.score = 99也可以修改啊，为什么要定义一个方法大费周折？因为在方法中，可以对参数做检查，避免传入无效的参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name, score):\n",
    "        self.__name = name\n",
    "        self.__score = score\n",
    "        \n",
    "    def get_name(self):\n",
    "        return self.__name\n",
    "    def get_score(self):\n",
    "        return self.__score\n",
    "    \n",
    "    def set_score(self, score):\n",
    "        if 0 <= score <= 100:\n",
    "            self.__score = score\n",
    "        else:\n",
    "            raise ValueError('bad score')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "需要注意的是，在Python中，变量名类似**\\_\\_xxx\\_\\_的，也就是以双下划线开头**，**并且以双下划线结尾的**，是特殊变量，**特殊变量是可以直接访问的，不是private变量，**所以，不能用__name__、__score__这样的变量名。\n",
    "\n",
    "有些时候，你会看到以**一个下划线开头的实例变量名**，比如_name，这样的实例变量外部是可以访问的，但是，按照约定俗成的规定，当你看到这样的变量时，意思就是，“虽然我可以被访问，但是，请把我视为私有变量，不要随意访问”。\n",
    "\n",
    "**双下划线开头的实例变量是不是一定不能从外部访问呢？**其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了**\\_Student__name，**所以，仍然可以**通过 \\__Student\\___name**来访问**__name**变量："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "bart = Student('aa',80)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'Student' object has no attribute '__name'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-26-b54cbc8ec6d2>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mbart\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'Student' object has no attribute '__name'"
     ]
    }
   ],
   "source": [
    "bart.__name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'aa'"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart._Student__name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但是强烈建议你不要这么干，因为**不同版本的Python解释器可能会把__name改成不同的变量名。**\n",
    "\n",
    "总的来说就是，Python本身没有任何机制阻止你干坏事，一切全靠自觉。\n",
    "\n",
    "最后注意下面的这种错误写法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Bart Simpson'"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart = Student('Bart Simpson', 59)\n",
    "bart.get_name()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'New Name'"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.__name = 'New Name' # 设置__name变量！\n",
    "bart.__name  #外部代码“成功”地设置了name变量，但实际上这个name变量和class内部的name变量不是一个变量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "表面上看，外部代码“成功”地设置了__name变量，但实际上这个__name变量和class内部的__name变量不是一个变量！内部的__name变量已经被Python解释器自动改成了_Student__name，而外部代码给bart新增了一个__name变量。不信试试："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "bart.get_name() # get_name()内部返回self.__name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# python中的继承和多态"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**继承是为了复用代码，并灵活扩展**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在OOP程序设计中，当我们定义一个class的时候，可以从某个现有的class继承，**新的class称为子类（Subclass），**\n",
    "而**被继承的class称为基类、父类或超类（Base class、Super class）。**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Animal(object):   #objiect是所有类的父类，也称根类\n",
    "    \n",
    "    def run(self):\n",
    "        print('Animal is running...')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当我们需要编写Dog和Cat类时，就可以直接从Animal类继承："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Dog(Animal):\n",
    "    pass\n",
    "\n",
    "class Cat(Animal):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于Dog来说，Animal就是它的父类，对于Animal来说，Dog就是它的子类。Cat和Dog类似。<br/>\n",
    "继承有什么好处？最大的好处是**子类获得了父类的全部功能。**由于Animial实现了run()方法，\n",
    "<br/>因此，Dog和Cat作为它的子类，什么事也没干，就自动拥有了run()方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Animal is running...\n",
      "Animal is running...\n"
     ]
    }
   ],
   "source": [
    "dog = Dog()\n",
    "dog.run()\n",
    "\n",
    "cat = Cat()\n",
    "cat.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "继承的第二个好处需要我们对**代码做一点改进**。你看到了，无论是Dog还是Cat，它们run()的时候，显示的都是Animal is running...，符合逻辑的做法是分别显示Dog is running...和Cat is running...，因此，对Dog和Cat类改进如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Dog(Animal):\n",
    "    def eat(self):\n",
    "        print('吃骨头')\n",
    "        \n",
    "    def run(self):\n",
    "        print('Dog is running...')\n",
    "\n",
    "class Cat(Animal):\n",
    "    def catch_mouth(self):\n",
    "        print('抓老鼠')\n",
    "    def run(self):\n",
    "        print('Cat is running...')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dog is running...\n",
      "Cat is running...\n"
     ]
    }
   ],
   "source": [
    "dog = Dog()\n",
    "dog.run()\n",
    "\n",
    "cat = Cat()\n",
    "cat.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "抓老鼠\n"
     ]
    }
   ],
   "source": [
    "cat.catch_mouth()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当**子类和父类都存在相同的run()方法时，我们说，子类的run()覆盖了父类的run()，**在代码运行的时候，总是会调用子类的run()。这样，我们就获得了继承的另一个好处：多态。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "要理解什么是多态，我们首先要对**数据类型**再作一点说明。当我们定义一个class的时候，我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型，比如str、list、dict没什么两样："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "a = list() # a是list类型\n",
    "b = Animal() # b是Animal类型\n",
    "c = Dog() # c是Dog类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "isinstance(a, list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(isinstance(b, Animal))\n",
    "isinstance(c, Dog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在继承关系中，如果一个实例的数据类型是某个子类，那它的数据类型也可以被看做是父类类型。但是，反过来把父类类型看成子类就不行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = Animal()\n",
    "isinstance(b, Dog)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# isinstance(c, object)\n",
    "isinstance(c, Animal)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**要理解多态的好处**，我们还需要再编写一个函数，这个函数接受一个Animal类型的变量："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Dog(Animal):\n",
    "     def run(self):\n",
    "        print('Dog is running...')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dog is running...\n"
     ]
    }
   ],
   "source": [
    "dog = Dog()\n",
    "dog.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dog is running...\n"
     ]
    }
   ],
   "source": [
    "# 定义一个函数，传入各种动物\n",
    "def duotai(animal):\n",
    "    animal.run()\n",
    "duotai(dog)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Animal is running...\n"
     ]
    }
   ],
   "source": [
    "duotai(Cat())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "看上去没啥意思，但是仔细想想，现在，如果我们再定义一个Tortoise类型，也从Animal派生：\n",
    "\n",
    "新增一个**Animal的子类，不必对duotai()做任何修改，**实际上，任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行，原因就在于多态。\n",
    "\n",
    "对于一个变量，我们只需要知道它是Animal类型，无需确切地知道它的子类型，就可以放心地调用run()方法，而**具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上，由运行时该对象的确切类型决定**，这就是多态真正的威力"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tortoise is running slowly...\n"
     ]
    }
   ],
   "source": [
    "class Tortoise(Animal):\n",
    "    def run(self):\n",
    "        print('Tortoise is running slowly...')\n",
    "\n",
    "duotai(Tortoise())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**小结**\n",
    "\n",
    "**静态语言 vs 动态语言**\n",
    "\n",
    "对于静态语言（例如Java，C++）来说，如果需要传入Animal类型，则传入的对象必须是Animal类型或者它的子类，否则，将无法调用run()方法。\n",
    "对于Python这样的动态语言来说，则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Animal:\n",
    "    def run(self):\n",
    "        raise AttributeError('子类必须实现这个方法')\n",
    "class People(Animal):\n",
    "    def run(self):\n",
    "        print('人正在走')\n",
    "class Pig(Animal):\n",
    "    def run(self):\n",
    "        print('pig is walking')\n",
    "class Dog(Animal):\n",
    "    def run(self):\n",
    "        print('dog is running')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "peo1=People()\n",
    "pig1=Pig()\n",
    "d1=Dog()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "人正在走\n",
      "pig is walking\n",
      "dog is running\n"
     ]
    }
   ],
   "source": [
    "peo1.run()\n",
    "pig1.run()\n",
    "d1.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pig is walking\n"
     ]
    }
   ],
   "source": [
    "def aniRun(animal):\n",
    "    animal.run()\n",
    "aniRun(pig1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **获取对象信息**\n",
    "\n",
    "当我们拿到一个对象的引用时，如何知道这个对象是什么类型、有哪些方法呢？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**使用type()**<br/>\n",
    "首先，我们来判断对象类型，使用type()函数,基本类型都可以用type()判断："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'int'>\n",
      "<class 'str'>\n",
      "<class 'NoneType'>\n"
     ]
    }
   ],
   "source": [
    "print(type(123))\n",
    "print(type('str'))\n",
    "print(type(None))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果一个变量指向函数或者类，也可以用type()判断："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'builtin_function_or_method'>\n",
      "<class 'list'>\n"
     ]
    }
   ],
   "source": [
    "print(type(abs))\n",
    "print(type(a))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但是type()函数返回的是什么类型呢？它返回对应的Class类型。如果我们要在if语句中判断，就需要比较两个变量的type类型是否相同："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "True\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "print(type(123)==type(456))\n",
    "print(type(123)==int)\n",
    "print(type('abc')==type('123'))\n",
    "print(type('abc')==str)\n",
    "print(type('abc')==type(123))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "判断基本数据类型可以直接写int，str等，但如果要判断一个对象是否是函数怎么办？可以使用types模块中定义的常量："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import types\n",
    "def fn():\n",
    "    pass\n",
    "type(fn)==types.FunctionType"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.fn()>"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(type(lambda x: x)==types.LambdaType)\n",
    "type((x for x in range(10)))==types.GeneratorType"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**使用isinstance()**\n",
    "\n",
    "对于class的继承关系来说，使用type()就很不方便。我们要判断class的类型，可以使用isinstance()函数。\n",
    "我们回顾上次的例子，如果继承关系是："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Husky(Dog):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "a = Animal()\n",
    "d = Dog()\n",
    "h = Husky()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "print(isinstance(h, Husky))\n",
    "print(isinstance(h, Dog))\n",
    "print(isinstance(h, Animal))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 85,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "isinstance(d, Husky)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**能用type()判断的基本类型也可以用isinstance()判断：**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "print(isinstance('a', str))\n",
    "print(isinstance(123, int))\n",
    "print(isinstance(b'a', bytes))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**判断一个变量是否是某些类型中的一种，比如下面的代码就可以判断是否是list或者tuple：**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "isinstance([1, 2, 3], (list, tuple))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "isinstance((1, 2, 3), (list, tuple))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**使用dir()**\n",
    "\n",
    "如果要获得一个对象的所有属性和方法，可以使用dir()函数，它返回一个包含字符串的list，比如，获得一个str对象的所有属性和方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__add__',\n",
       " '__class__',\n",
       " '__contains__',\n",
       " '__delattr__',\n",
       " '__dir__',\n",
       " '__doc__',\n",
       " '__eq__',\n",
       " '__format__',\n",
       " '__ge__',\n",
       " '__getattribute__',\n",
       " '__getitem__',\n",
       " '__getnewargs__',\n",
       " '__gt__',\n",
       " '__hash__',\n",
       " '__init__',\n",
       " '__init_subclass__',\n",
       " '__iter__',\n",
       " '__le__',\n",
       " '__len__',\n",
       " '__lt__',\n",
       " '__mod__',\n",
       " '__mul__',\n",
       " '__ne__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__rmod__',\n",
       " '__rmul__',\n",
       " '__setattr__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " 'capitalize',\n",
       " 'casefold',\n",
       " 'center',\n",
       " 'count',\n",
       " 'encode',\n",
       " 'endswith',\n",
       " 'expandtabs',\n",
       " 'find',\n",
       " 'format',\n",
       " 'format_map',\n",
       " 'index',\n",
       " 'isalnum',\n",
       " 'isalpha',\n",
       " 'isascii',\n",
       " 'isdecimal',\n",
       " 'isdigit',\n",
       " 'isidentifier',\n",
       " 'islower',\n",
       " 'isnumeric',\n",
       " 'isprintable',\n",
       " 'isspace',\n",
       " 'istitle',\n",
       " 'isupper',\n",
       " 'join',\n",
       " 'ljust',\n",
       " 'lower',\n",
       " 'lstrip',\n",
       " 'maketrans',\n",
       " 'partition',\n",
       " 'replace',\n",
       " 'rfind',\n",
       " 'rindex',\n",
       " 'rjust',\n",
       " 'rpartition',\n",
       " 'rsplit',\n",
       " 'rstrip',\n",
       " 'split',\n",
       " 'splitlines',\n",
       " 'startswith',\n",
       " 'strip',\n",
       " 'swapcase',\n",
       " 'title',\n",
       " 'translate',\n",
       " 'upper',\n",
       " 'zfill']"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dir('ABCd')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__class__',\n",
       " '__delattr__',\n",
       " '__dict__',\n",
       " '__dir__',\n",
       " '__doc__',\n",
       " '__eq__',\n",
       " '__format__',\n",
       " '__ge__',\n",
       " '__getattribute__',\n",
       " '__gt__',\n",
       " '__hash__',\n",
       " '__init__',\n",
       " '__init_subclass__',\n",
       " '__le__',\n",
       " '__lt__',\n",
       " '__module__',\n",
       " '__ne__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__setattr__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " '__weakref__',\n",
       " 'run']"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dir(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "类似**\\_\\_xxx\\_\\_的属性和方法在Python中都是有特殊用途的**，比如**\\_\\_len\\_\\_方法返回长度**。在Python中，如果你**调用len()函数试图获取一个对象的长度，实际上，在len()函数内部，它自动去调用该对象的\\_\\_len\\_\\_()方法，**所以，下面的代码是等价的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "print(len('ABC'))\n",
    "print('ABC'.__len__())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们自己写的类，如果也想用**len(myObj)**的话，就**自己写一个\\_\\_len\\_\\_()方法：**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "100"
      ]
     },
     "execution_count": 95,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class MyDog(object):\n",
    "    def __len__(self):\n",
    "        return 100\n",
    "\n",
    "dog = MyDog()\n",
    "len(dog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "配合**getattr()、setattr()以及hasattr()**，我们可以直接操作一个对象的状态："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class MyObject(object):\n",
    "    def __init__(self):\n",
    "        self.x = 9\n",
    "    def power(self):\n",
    "        return self.x * self.x\n",
    "\n",
    "obj = MyObject()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 97,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hasattr(obj, 'x') # 有属性'x'吗？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 98,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hasattr(obj, 'y') # 有属性'y'吗？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 99,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "setattr(obj, 'y', 19) # 设置一个属性'y'\n",
    "hasattr(obj, 'y') # 有属性'y'吗？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "19"
      ]
     },
     "execution_count": 100,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "getattr(obj, 'y') # 获取属性'y'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "obj.y # 获取属性'y'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'MyObject' object has no attribute 'z'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-101-d5c1c50d23bb>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# 如果试图获取不存在的属性，会抛出AttributeError的错误：\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mgetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'z'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# 获取属性'z'\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: 'MyObject' object has no attribute 'z'"
     ]
    }
   ],
   "source": [
    "# 如果试图获取不存在的属性，会抛出AttributeError的错误：\n",
    "getattr(obj, 'z') # 获取属性'z'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#可以传入一个default参数，如果属性不存在，就返回默认值：\n",
    "getattr(obj, 'z', 404) # 获取属性'z'，如果不存在，返回默认值404"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**也可以获得对象的方法：**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "hasattr(obj, 'power') # 有属性'power'吗？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "getattr(obj, 'power') # 获取属性'power'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<bound method MyObject.power of <__main__.MyObject object at 0x0000025127DDC470>>"
      ]
     },
     "execution_count": 102,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn\n",
    "fn # fn指向obj.power"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "fn() # 调用fn()与调用obj.power()是一样的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#通过内置的一系列函数，我们可以对任意一个Python对象进行剖析，拿到其内部的数据。\n",
    "#要注意的是，只有在不知道对象信息的时候，我们才会去获取对象信息。如果可以直接写：\n",
    "sum = obj.x + obj.y\n",
    "#就不要写：\n",
    "sum = getattr(obj, 'x') + getattr(obj, 'y')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 一个正确的用法的例子如下：\n",
    "def readImage(fp):\n",
    "    if hasattr(fp, 'read'):\n",
    "        return readData(fp)\n",
    "    return None\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "假设我们希望从文件流fp中读取图像，我们首先要判断该fp对象是否存在read方法，如果存在，则该对象是一个流，如果不存在，则无法读取。\n",
    "hasattr()就派上了用场。要注意，在Python这类动态语言中，有read()方法，不代表该fp对象就是一个文件流，它也可能是网络流，也可能\n",
    "是内存中的一个字节流，但只要read()方法返回的是有效的图像数据，就不影响读取图像的功能。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 实例属性和类属性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "由于Python是动态语言，根据类创建的实例可以任意绑定属性。\n",
    "给实例绑定属性的方法是通过**实例变量，或者通过self变量**："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "s = Student('Bob')\n",
    "s.score = 90"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Student类本身需要绑定一个属性呢？**可以直接在class中定义属性，这种属性是类属性，归Student类所有："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    name = 'Student'\n",
    "    sex = 'M'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当我们定义了一个类属性后，这个属性虽然归类所有，但**类的所有实例都可以访问到**。来测试一下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Student\n"
     ]
    }
   ],
   "source": [
    "# 创建实例s\n",
    "s = Student() \n",
    "\n",
    "# 打印name属性，因为实例并没有name属性，所以会继续查找class的name属性\n",
    "print(s.name) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Student\n"
     ]
    }
   ],
   "source": [
    "# 打印类的name属性\n",
    "print(Student.name) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Michael\n"
     ]
    }
   ],
   "source": [
    "s.name = 'Michael'  # 给实例绑定name属性\n",
    "print(s.name) # 由于实例属性优先级比类属性高，因此，它会屏蔽掉类的name属性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Student\n"
     ]
    }
   ],
   "source": [
    "print(Student.name) # 但是类属性并未消失，用Student.name仍然可以访问"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Student\n"
     ]
    }
   ],
   "source": [
    "del s.name # 如果删除实例的name属性\n",
    "print(s.name) # 再次调用s.name，由于实例的name属性没有找到，类的name属性就显示出来了"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "实例属性属于各个实例所有，互不干扰；\n",
    "\n",
    "类属性属于类所有，所有实例共享一个属性；\n",
    "\n",
    "不要对实例属性和类属性使用相同的名字，否则将产生难以发现的错误。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# python的动态绑定，体现动态语言的灵活性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#先定义class：\n",
    "class Student(object):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然后，尝试给实例绑定一个属性："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Michael\n"
     ]
    }
   ],
   "source": [
    "s = Student()\n",
    "s.name = 'Michael' # 动态给实例绑定一个属性\n",
    "print(s.name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给实例绑定方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def set_age(self, age): # 定义一个函数作为实例方法\n",
    "    self.age = age"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "s.set_age = set_age"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.set_age(s,4)\n",
    "s.age"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "实例绑定一个方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def set_name(self, name): # 定义一个函数作为实例方法\n",
    "    self.name = name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from types import MethodType\n",
    "# 给实例s绑定方法set_age()\n",
    "s.set_name = MethodType(set_name, s) \n",
    "\n",
    "s.set_name('bill') # 调用实例方法\n",
    "s.name # 测试结果"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给一个实例绑定的方法，对另一个实例是不起作用的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'Student' object has no attribute 'set_age'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-14-76d19adbb2ee>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0ms2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mStudent\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# 创建新的实例\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0ms2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset_age\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m25\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# 尝试调用方法\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: 'Student' object has no attribute 'set_age'"
     ]
    }
   ],
   "source": [
    "s2 = Student() # 创建新的实例\n",
    "s2.set_age(25) # 尝试调用方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为了给所有实例都绑定方法，可以**给class绑定方法：**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def set_score(self, score):\n",
    "    self.score = score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给类绑定方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "Student.set_score = MethodType(set_score,Student)\n",
    "s3 = Student()\n",
    "s3.set_score(90)\n",
    "print(s3.score)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给类绑定方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "Student.set_score = set_score #给class绑定方法 \n",
    "s4 = Student() # 创建新的实例\n",
    "s4.set_score(100)\n",
    "print(s4.score)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**使用\\_\\_slots\\_\\_**<br/>\n",
    "但是，如果我们想要限制实例的属性怎么办？比如，只允许对Student实例添加name和age属性。<br/>\n",
    "为了达到限制的目的，Python允许在定义class的时候，定义一个特殊的__slots__变量，来限制该class实例能添加的属性："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "s = Student() # 创建新的实例\n",
    "s.name = 'Michael' # 绑定属性'name'\n",
    "s.age = 25 # 绑定属性'age'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "s.score = 99 # 绑定属性'score'失败"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用__slots__要注意，__slots__定义的属性仅对当前类实例起作用，对继承的子类是不起作用的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class GraduateStudent(Student):\n",
    "    pass\n",
    "\n",
    "g = GraduateStudent()\n",
    "g.score = 9999"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import abc\n",
    "class Animal(metaclass=abc.ABCMeta): #同一类事物:动物\n",
    "    @abc.abstractmethod\n",
    "    def talk(self):\n",
    "        pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class People(Animal): #动物的形态之一:人\n",
    "    def talk(self):\n",
    "        print('say hello')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Dog(Animal): #动物的形态之二:狗\n",
    "    def talk(self):\n",
    "        print('say wangwang')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Pig(Animal): #动物的形态之三:猪\n",
    "    def talk(self):\n",
    "        print('say aoao')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "文件有多种形态：文件、文本文件、可执行文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import abc\n",
    "class File(metaclass=abc.ABCMeta): #同一类事物:文件\n",
    "    @abc.abstractmethod\n",
    "    def click(self):\n",
    "        pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Text(File): #文件的形态之一:文本文件\n",
    "    def click(self):\n",
    "        print('open file')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class ExeFile(File): #文件的形态之二:可执行文件\n",
    "    def click(self):\n",
    "        print('execute file')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "二 多态性\n",
    "\n",
    "（1）什么是多态性（注意：**多态与多态性是两种概念**）\n",
    "\n",
    "**多态性**是指具有不同功能的函数可以使用相同的函数名，这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性：向不同的对象发送同一条消息，不同的对象在接收时会产生不同的行为（即方法）。也就是说，每个对象可以用自己的方式去响应共同的消息。所谓消息，就是调用函数，不同的行为就是指不同的实现，即执行不同的函数。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#多态性：一种调用方式，不同的执行效果（多态性）\n",
    "def func(obj):\n",
    "    obj.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "func(peo1)\n",
    "func(pig1)\n",
    "func(d1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "peo1.run()\n",
    "pig1.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 多态性依赖于：继承\n",
    "##多态性：定义统一的接口，\n",
    "def func(obj): #obj这个参数没有类型限制，可以传入不同类型的值\n",
    "    obj.run() #调用的逻辑都一样，执行的结果却不一样"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "func(peo1)\n",
    "func(pig1)\n",
    "func(d1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def func(animal): #参数animal就是对态性的体现\n",
    "    animal.talk()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "people1=People() #产生一个人的对象\n",
    "pig1=Pig() #产生一个猪的对象\n",
    "dog1=Dog() #产生一个狗的对象\n",
    "func(people1) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "func(pig1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "func(dog1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "综上可以说，**多态性是一个接口（函数func）**,**多种实现（如f.click()）**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "二、为什么要用多态性（多态性的好处）\n",
    "\n",
    "其实大家从上面多态性的例子可以看出，我们并没有增加上面新的知识，也就是说Python本身就是支持多态性的，这么做的好处是什么呢？\n",
    "（1）增加了程序的灵活性\n",
    "\t　　以不变应万变，不论对象千变万化，使用者都是同一种形式去调用，如func(animal)\n",
    "（2）增加了程序额可扩展性\n",
    "\t　　通过继承animal类创建了一个新的类，使用者无需更改自己的代码，还是用func(animal)去调用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 多重继承\n",
    "\n",
    "继承是面向对象编程的一个重要的方式，因为通过继承，子类就可以扩展父类的功能。"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "Animal类层次的设计，假设我们要实现以下4种动物：\n",
    "\n",
    "Dog - 狗狗；\n",
    "Bat - 蝙蝠；\n",
    "Parrot - 鹦鹉；\n",
    "Ostrich - 鸵鸟。"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "如果按照哺乳动物和鸟类归类，我们可以设计出这样的类的层次：\n",
    "\n",
    "                ┌───────────────┐\n",
    "                │    Animal     │\n",
    "                └───────────────┘\n",
    "                        │\n",
    "           ┌────────────┴────────────┐\n",
    "           │                                                  │\n",
    "           ▼                                                  ▼\n",
    "    ┌─────────────┐           ┌─────────────┐\n",
    "    │   Mammal    │           │                         Bird     │\n",
    "    └─────────────┘           └─────────────┘\n",
    "           │                         │\n",
    "     ┌─────┴──────┐            ┌─────┴──────┐\n",
    "     │            │            │            │\n",
    "     ▼            ▼            ▼            ▼\n",
    "┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐\n",
    "│   Dog   │  │   Bat   │  │ Parrot  │  │ Ostrich │\n",
    "└─────────┘  └─────────┘  └─────────┘  └─────────┘\n",
    "但是如果按照“能跑”和“能飞”来归类，我们就应该设计出这样的类的层次：\n",
    "\n",
    "                ┌───────────────┐\n",
    "                │    Animal     │\n",
    "                └───────────────┘\n",
    "                        │\n",
    "           ┌────────────┴────────────┐\n",
    "           │                         │\n",
    "           ▼                         ▼\n",
    "    ┌─────────────┐           ┌─────────────┐\n",
    "    │  Runnable   │           │   Flyable   │\n",
    "    └─────────────┘           └─────────────┘\n",
    "           │                         │\n",
    "     ┌─────┴──────┐            ┌─────┴──────┐\n",
    "     │            │            │            │\n",
    "     ▼            ▼            ▼            ▼\n",
    "┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐\n",
    "│   Dog   │  │ Ostrich │  │ Parrot  │  │   Bat   │\n",
    "└─────────┘  └─────────┘  └─────────┘  └─────────┘\n",
    "如果要把上面的两种分类都包含进来，我们就得设计更多的层次：\n",
    "\n",
    "哺乳类：能跑的哺乳类，能飞的哺乳类；\n",
    "鸟类：能跑的鸟类，能飞的鸟类。\n",
    "这么一来，类的层次就复杂了：\n",
    "\n",
    "                ┌───────────────┐\n",
    "                │    Animal     │\n",
    "                └───────────────┘\n",
    "                        │\n",
    "           ┌────────────┴────────────┐\n",
    "           │                         │\n",
    "           ▼                         ▼\n",
    "    ┌─────────────┐           ┌─────────────┐\n",
    "    │   Mammal    │           │    Bird     │\n",
    "    └─────────────┘           └─────────────┘\n",
    "           │                         │\n",
    "     ┌─────┴──────┐            ┌─────┴──────┐\n",
    "     │            │            │            │\n",
    "     ▼            ▼            ▼            ▼\n",
    "┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐\n",
    "│  MRun   │  │  MFly   │  │  BRun   │  │  BFly   │\n",
    "└─────────┘  └─────────┘  └─────────┘  └─────────┘\n",
    "     │            │            │            │\n",
    "     │            │            │            │\n",
    "     ▼            ▼            ▼            ▼\n",
    "┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐\n",
    "│   Dog   │  │   Bat   │  │ Ostrich │  │ Parrot  │\n",
    "└─────────┘  └─────────┘  └─────────┘  └─────────┘\n",
    "如果要再增加“宠物类”和“非宠物类”，这么搞下去，类的数量会呈指数增长，很明显这样设计是不行的。\n",
    "\n",
    "正确的做法是采用多重继承。首先，主要的类层次仍按照哺乳类和鸟类设计："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Animal(object):\n",
    "    pass\n",
    "\n",
    "# 大类:\n",
    "class Mammal(Animal):\n",
    "    pass\n",
    "\n",
    "class Bird(Animal):\n",
    "    pass\n",
    "\n",
    "# 各种动物:\n",
    "class Dog(Mammal):\n",
    "    pass\n",
    "\n",
    "class Bat(Mammal):\n",
    "    pass\n",
    "\n",
    "class Parrot(Bird):\n",
    "    pass\n",
    "\n",
    "class Ostrich(Bird):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在，我们要给动物再加上Runnable和Flyable的功能，只需要先定义好Runnable和Flyable的类："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Runnable(object):\n",
    "    def run(self):\n",
    "        print('Running...')\n",
    "\n",
    "class Flyable(object):\n",
    "    def fly(self):\n",
    "        print('Flying...')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "type(Runnable)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "type(dog1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于需要Runnable功能的动物，就多继承一个Runnable，例如Dog："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Dog(Mammal, Runnable):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "dog1 = Dog()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "dog1.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**MixIn**\n",
    "\n",
    "在设计类的继承关系时，通常，主线都是单一继承下来的，例如，Ostrich继承自Bird。但是，如果需要“混入”额外的功能，通过多重继承就可以实现，比如，让Ostrich除了继承自Bird外，再同时继承Runnable。这种设计通常称之为MixIn。\n",
    "\n",
    "为了更好地看出继承关系，我们把Runnable和Flyable改为RunnableMixIn和FlyableMixIn。类似的，你还可以定义出肉食动物CarnivorousMixIn和植食动物HerbivoresMixIn，让某个动物同时拥有好几个MixIn："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "比如，编写一个多进程模式的TCP服务，定义如下：\n",
    "class MyTCPServer(TCPServer, ForkingMixIn):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "编写一个多线程模式的UDP服务，定义如下：\n",
    "class MyUDPServer(UDPServer, ThreadingMixIn):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**通过type()函数创建类**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def fn1(self, name='dog'): # 定义函数\n",
    "    print('Hello, %s.' % name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 使用type（）创建class\n",
    "Dog1 = type('Dog_1', (Mammal,Runnable), dict(hello=fn1)) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "dog2 = Dog1()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "dog2.run"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "dog2.hello()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用元类\n",
    "\n",
    "\n",
    "**type()**\n",
    "\n",
    "动态语言和静态语言最大的不同，就是函数和类的定义，不是编译时定义的，而是运行时动态创建的。\n",
    "\n",
    "比方说我们要定义一个Hello的class，就写一个hello.py模块："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Hello(object):\n",
    "    def hello(self, name='world'):\n",
    "        print('Hello, %s.' % name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当Python解释器载入hello模块时，就会依次执行该模块的所有语句，执行结果就是动态创建出一个Hello的class对象，测试如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "h = Hello()\n",
    "h.hello()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "print(type(Hello))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "print(type(h))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**type()**函数可以查看一个类型或变量的类型，Hello是一个class，它的类型就是type，而h是一个实例，它的类型就是class Hello。\n",
    "\n",
    "我们说class的定义是运行时动态创建的，而创建class的方法就是使用type()函数。\n",
    "\n",
    "**type()函数既可以返回一个对象的类型，又可以创建出新的类型**，比如，我们可以**通过type()函数创建出Hello类，**而无需通过class Hello(object)...的定义："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def fn(self, name='world'): # 先定义函数\n",
    "    print('Hello, %s.' % name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 使用type（）创建Hello class\n",
    "Hello = type('Hello', (object,), dict(hello=fn,hello2=fn))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "h = Hello()\n",
    "h.hello2()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "print(type(Hello))\n",
    "print(type(h))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "要创建一个class对象，**type()函数依次传入3个参数：**\n",
    "\n",
    "**class的名称；**<br/>\n",
    "**继承的父类集合，**注意Python支持多重继承，如果只有一个父类，别忘了tuple的单元素写法；<br/>\n",
    "**class的方法名称与函数绑定**，这里我们把函数fn绑定到方法名hello上。<br/>\n",
    "通过type()函数创建的类和直接写class是完全一样的，因为Python解释器遇到class定义时，仅仅是扫描一下class定义的语法，然后调用type()函数创建出class。\n",
    "\n",
    "正常情况下，我们都用class Xxx...来定义类，但是，type()函数也允许我们动态创建出类来，也就是说，动态语言本身支持运行期动态创建类，这和静态语言有非常大的不同，要在静态语言运行期创建类，必须构造源代码字符串再调用编译器，或者借助一些工具生成字节码实现，本质上都是动态编译，会非常复杂。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# metaclass\n",
    "\n",
    "除了使用**$type()$**动态创建类以外，要控制类的创建行为，还可以使用metaclass。\n",
    "\n",
    "metaclass，直译为元类，简单的解释就是：\n",
    "\n",
    "当我们定义了类以后，就可以根据这个类创建出实例，所以：先定义类，然后创建实例。\n",
    "\n",
    "但是如果我们想创建出类呢？那就必须根据metaclass创建出类，所以：先定义metaclass，然后创建类。\n",
    "\n",
    "连接起来就是：先定义metaclass，就可以创建类，最后创建实例。\n",
    "\n",
    "所以，metaclass允许你创建类或者修改类。换句话说，你可以把类看成是metaclass创建出来的“实例”。\n",
    "\n",
    "metaclass是Python面向对象里最难理解，也是最难使用的魔术代码。正常情况下，你不会碰到需要使用metaclass的情况，所以，以下内容看不懂也没关系，因为基本上你不会用到。\n",
    "\n",
    "我们先看一个简单的例子，这个metaclass可以给我们自定义的MyList增加一个add方法：\n",
    "\n",
    "定义ListMetaclass，按照默认习惯，metaclass的类名总是以Metaclass结尾，以便清楚地表示这是一个metaclass："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# metaclass是类的模板，所以必须从`type`类型派生：\n",
    "class ListMetaclass(type):\n",
    "    def __new__(cls, name, bases, attrs):\n",
    "        attrs['add'] = lambda self, value: self.append(value)\n",
    "        return type.__new__(cls, name, bases, attrs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 有了ListMetaclass，我们在定义类的时候还要指示使用ListMetaclass来定制类，传入关键字参数metaclass：\n",
    "class MyList(list, metaclass=ListMetaclass):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当我们传入关键字参数metaclass时，魔术就生效了，它指示Python解释器在创建MyList时，要通过ListMetaclass.__new__()来创建，在此，我们可以修改类的定义，比如，加上新的方法，然后，返回修改后的定义。"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "__new__()方法接收到的参数依次是：\n",
    "1、当前准备创建的类的对象；\n",
    "2、类的名字；\n",
    "3、类继承的父类集合；\n",
    "4、类的方法集合。\n",
    "测试一下MyList是否可以调用add()方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "L = MyList()\n",
    "L.add(1)\n",
    "L"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 而普通的list没有add()方法：\n",
    "L2 = list()\n",
    "L2.add(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "动态修改有什么意义？直接在MyList定义中写上add()方法不是更简单吗？正常情况下，确实应该直接写，通过metaclass修改纯属变态。\n",
    "\n",
    "但是，总会遇到需要通过metaclass修改类定义的。ORM就是一个典型的例子。\n",
    "\n",
    "ORM全称“Object Relational Mapping”，即对象-关系映射，就是把关系数据库的一行映射为一个对象，也就是一个类对应一个表，这样，写代码更简单，不用直接操作SQL语句。\n",
    "\n",
    "要编写一个ORM框架，所有的类都只能动态定义，因为只有使用者才能根据表的结构定义出对应的类来。\n",
    "\n",
    "让我们来尝试编写一个ORM框架。\n",
    "\n",
    "编写底层模块的第一步，就是先把调用接口写出来。比如，使用者如果使用这个ORM框架，想定义一个User类来操作对应的数据库表User，我们期待他写出这样的代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class User(Model):\n",
    "    # 定义类的属性到列的映射：\n",
    "    id = IntegerField('id')\n",
    "    name = StringField('username')\n",
    "    email = StringField('email')\n",
    "    password = StringField('password')\n",
    "\n",
    "# 创建一个实例：\n",
    "u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')\n",
    "# 保存到数据库：\n",
    "u.save()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "其中，父类Model和属性类型StringField、IntegerField是由ORM框架提供的，剩下的魔术方法比如save()全部由metaclass自动完成。虽然metaclass的编写会比较复杂，但ORM的使用者用起来却异常简单。\n",
    "\n",
    "现在，我们就按上面的接口来实现该ORM。\n",
    "\n",
    "首先来定义Field类，它负责保存数据库表的字段名和字段类型："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Field(object):\n",
    "    def __init__(self, name, column_type):\n",
    "        self.name = name\n",
    "        self.column_type = column_type\n",
    "    def __str__(self):\n",
    "        return '<%s:%s>' % (self.__class__.__name__, self.name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " 在Field的基础上，进一步定义各种类型的Field，比如StringField，IntegerField等等："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class StringField(Field):\n",
    "    def __init__(self, name):\n",
    "        super(StringField, self).__init__(name, 'varchar(100)')\n",
    "        \n",
    "class IntegerField(Field):\n",
    "    def __init__(self, name):\n",
    "        super(IntegerField, self).__init__(name, 'bigint')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下一步，就是编写最复杂的ModelMetaclass了："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class ModelMetaclass(type):\n",
    "\n",
    "    def __new__(cls, name, bases, attrs):\n",
    "        if name=='Model':\n",
    "            return type.__new__(cls, name, bases, attrs)\n",
    "        print('Found model: %s' % name)\n",
    "        mappings = dict()\n",
    "        for k, v in attrs.items():\n",
    "            if isinstance(v, Field):\n",
    "                print('Found mapping: %s ==> %s' % (k, v))\n",
    "                mappings[k] = v\n",
    "        for k in mappings.keys():\n",
    "            attrs.pop(k)\n",
    "        attrs['__mappings__'] = mappings # 保存属性和列的映射关系\n",
    "        attrs['__table__'] = name # 假设表名和类名一致\n",
    "        return type.__new__(cls, name, bases, attrs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以及基类Model："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Model(dict, metaclass=ModelMetaclass):\n",
    "\n",
    "    def __init__(self, **kw):\n",
    "        super(Model, self).__init__(**kw)\n",
    "\n",
    "    def __getattr__(self, key):\n",
    "        try:\n",
    "            return self[key]\n",
    "        except KeyError:\n",
    "            raise AttributeError(r\"'Model' object has no attribute '%s'\" % key)\n",
    "\n",
    "    def __setattr__(self, key, value):\n",
    "        self[key] = value\n",
    "\n",
    "    def save(self):\n",
    "        fields = []\n",
    "        params = []\n",
    "        args = []\n",
    "        for k, v in self.__mappings__.items():\n",
    "            fields.append(v.name)\n",
    "            params.append('?')\n",
    "            args.append(getattr(self, k, None))\n",
    "        sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))\n",
    "        print('SQL: %s' % sql)\n",
    "        print('ARGS: %s' % str(args))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当用户定义一个class User(Model)时，Python解释器首先在当前类User的定义中查找metaclass，如果没有找到，就继续在父类Model中查找metaclass，找到了，就使用Model中定义的metaclass的ModelMetaclass来创建User类，也就是说，metaclass可以隐式地继承到子类，但子类自己却感觉不到。\n",
    "\n",
    "在ModelMetaclass中，一共做了几件事情：\n",
    "\n",
    "排除掉对Model类的修改；\n",
    "\n",
    "在当前类（比如User）中查找定义的类的所有属性，如果找到一个Field属性，就把它保存到一个__mappings__的dict中，同时从类属性中删除该Field属性，否则，容易造成运行时错误（实例的属性会遮盖类的同名属性）；\n",
    "\n",
    "把表名保存到__table__中，这里简化为表名默认为类名。\n",
    "\n",
    "在Model类中，就可以定义各种操作数据库的方法，比如save()，delete()，find()，update等等。\n",
    "\n",
    "我们实现了save()方法，把一个实例保存到数据库中。因为有表名，属性到字段的映射和属性值的集合，就可以构造出INSERT语句。\n",
    "\n",
    "编写代码试试："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')\n",
    "u.save()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:py_36] *",
   "language": "python",
   "name": "conda-env-py_36-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.0"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
