{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 类和实例\n",
    "\n",
    "面向对象最重要的概念就是类（Class）和实例（Instance），必须牢记类是抽象的模板，比如Student类，而实例是根据类创建出来的一个个具体的“对象”，每个对象都拥有相同的方法，但各自的数据可能不同。\n",
    "\n",
    "仍以Student类为例，在Python中，定义类是通过**class关键字**：\n",
    "\n",
    "class Student(object):\n",
    "    pass\n",
    "\n",
    "class后面紧接着是类名，即Student，类名通常是大写开头的单词，紧接着是(object)，表示该类是从哪个类继承下来的，继承的概念我们后面再讲，通常，如果没有合适的继承类，就使用object类，这是所有类最终都会继承的类。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义一个空类\n",
    "定义好了**Student类**，就可以根据Student类创建出**Student的实例**，创建实例是通过类名+()实现的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "class后面紧接着是类名，即Student，类名通常是大写开头的单词，紧接着是**(object)**，表示该类是**从哪个类继承**下来的，继承的概念我们后面再讲，通常，如果没有合适的继承类，就使用object类，这是所有类最终都会继承的类。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 生成类的实例\n",
    "定义好了Student类，就可以根据Student类创建出Student的实例，创建实例是通过类名+()实现的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.Student at 0x2360908c128>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart = Student()\n",
    "bart"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "__main__.Student"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Student"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到，变量**bart**指向的就是一个**Student的实例**，后面的0x10a67a590是内存地址，每个object的地址都不一样，而Student本身则是一个类。\n",
    "\n",
    "### 自由地给一个**实例变量动态绑定属性**\n",
    "\n",
    "比如，给实例**bart绑定一个name**属性：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Bart Simpson'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.name = 'Bart Simpson'\n",
    "bart.name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 构造函数__init__()\n",
    "**类可以起到模板**的作用，因此，可以在创建实例的时候，把一些我们认为必须绑定的属性强制填写进去。<br/>\n",
    "通过定义一个特殊的__init__方法，在创建实例的时候，就把name，score等属性绑上去："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "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": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Bart Simpson'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart = Student('Bart Simpson', 59)\n",
    "bart.name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "59"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "和普通的函数相比，在**类中定义的函数只有一点不同，就是第一个参数永远是实例变量self**，并且，调用时，不用传递该参数。除此之外，类的方法和普通函数没有什么区别，\n",
    "所以，你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **数据封装**\n",
    "\n",
    "面向对象编程的一个重要特点就是数据封装。在上面的Student类中，每个实例就拥有**各自的name和score**这些数据。\n",
    "\n",
    "**通过外部函数**来访问这些数据，比如打印一个学生的成绩："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "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类的内部**定义访问数据的函数，这样，就把“数据”给封装起来了。<br/>\n",
    "这些封装数据的函数是和Student类本身是关联起来的，我们称之为类的方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "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))\n",
    "\n",
    "bart = Student('Bart Simpson', 59)\n",
    "bart.print_score()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "要定义一个方法，除了第一个参数是self外，其他和普通函数一样。要调用一个方法，只需要在实例变量上直接调用，除了self不用传递，其他参数正常传入："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "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": [
    "这样一来，我们从外部看Student类，就只需要知道，创建实例需要给出name和score，而如何打印，都是在Student类的内部定义的，\n",
    "这些数据和逻辑被“封装”起来了，调用很容易，但却不用知道内部实现的细节。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "封装的另一个好处是可以给**Student类增加新的方法**，比如get_grade："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Student(object):\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": "markdown",
   "metadata": {},
   "source": [
    "同样的，get_grade方法可以直接在实例变量上调用，不需要知道内部实现细节："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2431103239304\n",
      "2431103239848\n",
      ".....bbb\n"
     ]
    }
   ],
   "source": [
    "#  普通函数重名那么会覆盖,不使用Class那么所有函数不能重名.  ---不能适应大规模的编程项目\n",
    "def ff():\n",
    "    print('.....aaa')\n",
    "print(id(ff))\n",
    "    \n",
    "def ff():\n",
    "    print('.....bbb')\n",
    "print(id(ff))\n",
    "ff()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "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": 14,
   "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",
    "### 实例属性\n",
    "Student类的定义来看，外部代码还是可以自由地修改一个实例的name、score属性："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "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": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "59"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart = Student('Bart Simpson', 59)\n",
    "bart.score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "99"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.score = 99\n",
    "bart.score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 私有属性\n",
    "如果要让内部属性不被外部访问，可以把属性的名称前加上**两个下划线__**，在Python中，实例的变量名如果以__开头，就变成了一个私有变量（private），\n",
    "只有内部可以访问，外部不能访问，所以，我们把Student类改一改："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "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": [
    "改完后，对于外部代码来说，没什么变动，但是已经无法从外部访问实例变量.__name和实例变量.__score了："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'Student' object has no attribute '__score'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-19-3fcac74db37e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0mbart\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mStudent\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Bart Simpson'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m59\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;31m# bart.__name = 'BS'  # 动态绑定了__name\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mbart\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__score\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: 'Student' object has no attribute '__score'"
     ]
    }
   ],
   "source": [
    "bart = Student('Bart Simpson', 59)\n",
    "# bart.__name = 'BS'  # 动态绑定了__name\n",
    "bart.__score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这样就确保了外部代码不能随意修改对象内部的状态，这样通过访问限制的保护，代码更加健壮。\n",
    "\n",
    "但是如果外部代码要**获取name和score**怎么办？可以给Student类增加get_name和get_score这样的方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "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))\n",
    "        \n",
    "    def get_name(self):\n",
    "        return self.__name\n",
    "    def get_score(self):\n",
    "        return self.__score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果又要允许**外部代码修改score**怎么办？可以再给Student类增加set_score方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "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))\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",
    "        self.__score = score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你也许会问，原先那种直接通过bart.score = 99也可以修改啊，为什么要定义一个方法大费周折？<br/>\n",
    "因为在方法中，可以对参数做检查，避免传入无效的参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "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))\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": [
    "**需要注意:<br/>**\n",
    "在Python中，变量名类似__xxx__的，也就是以**双下划线开头，并且以双下划线结尾的，是特殊变量**，特殊变量是可以直接访问的，不是private变量，所以，不能用__name__、__score__这样的变量名。\n",
    "\n",
    "有些时候，你会看到以**一个下划线开头的实例变量名**，比如_name，这样的实例变量外部是可以访问的，但是，按照约定俗成的规定，当你看到这样的变量时，意思就是，“虽然我可以被访问，但是，请把我视为私有变量，不要随意访问”。\n",
    "\n",
    "双下划线开头的实例变量是不是一定不能从外部访问呢？其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name，所以，**仍然可以通过_Student__name来访问__name变量**："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Bart Simpson: 59\n"
     ]
    }
   ],
   "source": [
    "bart = Student('Bart Simpson', 59)\n",
    "bart.print_score()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'Student' object has no attribute '__name'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-36-1e120ece361e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mbart\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__name\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: 'Student' object has no attribute '__name'"
     ]
    }
   ],
   "source": [
    "bart.__name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('Bart Simpson', 59)"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart._Student__name, bart._Student__score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但是强烈建议你不要这么干，因为不同版本的Python解释器可能会把__name改成不同的变量名。\n",
    "\n",
    "总的来说就是，Python本身没有任何机制阻止你干坏事，一切全靠自觉。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Bart Simpson'"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart = Student('Bart Simpson', 59)\n",
    "bart.get_name()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'New Name'"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.__name = 'New Name' # 设置__name变量！\n",
    "bart.__name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "表面上看，外部代码“成功”地设置了__name变量，但实际上这个__name变量和class内部的__name变量不是一个变量！内部的__name变量已经被Python解释器自动改成了_Student__name，而外部代码给bart新增了一个__name变量。不信试试："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Bart Simpson'"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bart.get_name() # get_name()内部返回self.__name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 类属性、实例属性、类方法、实例方法以及静态方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1、类属性就是类对象所拥有的属性，它被所有类对象的实例对象所共有，在内存中只存在一个副本"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "jack\n",
      "jack\n"
     ]
    }
   ],
   "source": [
    "class People:\n",
    "    name = 'jack'  #公有的类属性\n",
    "    __age = 12     #私有的类属性\n",
    "    \n",
    "p = People()\n",
    " \n",
    "print (p.name)             #正确\n",
    "print (People.name)        #正确\n",
    "# print (p.__age)            #错误，不能在类外通过实例对象访问私有的类属性\n",
    "# print (People.__age)       #错误，不能在类外通过类对象访问私有的类属性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2、实例属性是不需要在类中显示定义的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class People:\n",
    "    name = 'jack'\n",
    " \n",
    "p = People()\n",
    "\n",
    "# 动态绑定age属性\n",
    "p.age =12  \n",
    "print (p.name)    #正确\n",
    "print( p.age)     #正确\n",
    " \n",
    "print (People.name)    #正确\n",
    "# print (People.age)     #错误"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**如果需要在类外修改类属性，必须通过类对象去引用然后进行修改。**<br/>\n",
    "**如果通过实例对象去引用，会产生一个同名的实例属性**，这种方式修改的是实例属性，不会影响到类属性，并且之后如果通过实例对象去引用该名称的属性，实例属性会强制屏蔽掉类属性，即引用的是实例属性，除非删除了该实例属性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "china\n",
      "china\n"
     ]
    }
   ],
   "source": [
    "class People:\n",
    "    country = 'china'\n",
    " \n",
    "print (People.country)  # 类属性\n",
    "p =People()\n",
    "print (p.country)  # 通过实例调用类属性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "japan\n",
      "china\n"
     ]
    }
   ],
   "source": [
    "p.country = 'japan'  # 在实例上绑定属性\n",
    "print (p.country)      #实例属性会屏蔽掉同名的类属性\n",
    "print (People.country)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "china\n"
     ]
    }
   ],
   "source": [
    "del p.country    #删除实例属性\n",
    "print (p.country)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 类方法、实例方法和静态方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 类方法：类方法的第一个参数是类对象cls，那么通过cls引用的必定是类对象的属性和方法；\n",
    "是类对象所拥有的方法，需要用修饰器\"@classmethod\"来标识其为类方法，对于类方法，第一个参数必须是类对象，一般以\"cls\"作为第一个参数（当然可以用其他名称的变量作为其第一个参数，但是大部分人都习惯以'cls'作为第一个参数的名字，就最好用'cls'了），能够通过实例对象和类对象去访问。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "china\n",
      "china\n",
      "fn1\n"
     ]
    }
   ],
   "source": [
    "class People:\n",
    "    country = 'china'\n",
    "    \n",
    "    #类方法，用classmethod来进行修饰，可以用实例引用，也可通过类引用\n",
    "    @classmethod\n",
    "    def getCountry(cls):\n",
    "        return cls.country\n",
    "    \n",
    "    #实例方法，只能用实例引用，不能用类名引用\n",
    "    def fn1(self):\n",
    "        print('fn1')\n",
    " \n",
    "p = People()\n",
    "print(p.getCountry())        #用实例对象引用\n",
    "print(People.getCountry() )  #通过类对象引用\n",
    "\n",
    "p.fn1()         #正确，可以用过实例对象引用\n",
    "# People.fn1()  # 错误，不能通过类对象引用实例方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'china'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# People.country\n",
    "p.country"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**类方法另一用途**就是可以对类属性进行修改："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "china\n",
      "china\n",
      "japan\n",
      "japan\n"
     ]
    }
   ],
   "source": [
    "class People:\n",
    "    country = 'china'\n",
    "    \n",
    "    #类方法，用classmethod来进行修饰\n",
    "    @classmethod\n",
    "    def getCountry(cls):\n",
    "        return cls.country\n",
    "        \n",
    "    @classmethod\n",
    "    def setCountry(cls,country):\n",
    "        cls.country = country\n",
    "        \n",
    " \n",
    "p = People()\n",
    "print(p.getCountry())    #可以用过实例对象引用\n",
    "print(People.getCountry())    #可以通过类对象引用\n",
    " \n",
    "p.setCountry('japan')   \n",
    " \n",
    "print(p.getCountry() )  \n",
    "print(People.getCountry())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 实例方法： 在类外,实例方法只能通过实例对象去调用，不能通过其他方式去调用。\n",
    "#### 实例方法的第一个参数是实例对象self，那么通过self引用的可能是类属性、也有可能是实例属性（这个需要具体分析），不过在存在相同名称的类属性和实例属性的情况下，实例属性优先级更高。<br/>\n",
    " 在类中最常定义的成员方法，它**至少有一个参数**并且必须以**实例对象作为其第一个参数，一般以名为'self'的变量**作为第一个参数（当然可以以其他名称的变量作为第一个参数）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class People:\n",
    "    country = 'china'\n",
    "    \n",
    "    #实例方法\n",
    "    def getCountry(self):\n",
    "        return self.country\n",
    "        \n",
    "p = People()\n",
    "print(p.getCountry())         #正确，可以用过实例对象引用\n",
    "# print People.getCountry()    #错误，不能通过类对象引用实例方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 静态方法\n",
    "需要通过**修饰器\"@staticmethod\"来进行修饰**，静态方法不需要多定义参数。<br/>\n",
    "静态方法的调用，既可以使用类名，也可以使用类对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "class People:\n",
    "    country = 'china'\n",
    "    \n",
    "    @staticmethod\n",
    "    #静态方法,不需要参数,\n",
    "    def getCountry():\n",
    "        return People.country\n",
    "    \n",
    "    # 相同名称的函数\n",
    "    def fn1(self):\n",
    "        print('fn1 实例方法')\n",
    "    @classmethod    #相当于执行了语句：fn1 = classmethod(fn1)\n",
    "    def fn1(cls):\n",
    "        print('fn1 类方法') # 同名方法时，类方法会覆盖实例方法\n",
    "    @staticmethod\n",
    "    def fn1():\n",
    "        print('fn1 静态方法') # 同名方法时，静态方法会覆盖类方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "china\n",
      "china\n",
      "jap\n",
      "china\n"
     ]
    }
   ],
   "source": [
    "p = People()\n",
    "print(p.getCountry())       # 可以通过实例调用静态方法\n",
    "print(People.getCountry())  # 可以通过类调用静态方法\n",
    "p.country = 'jap'\n",
    "print(p.country)\n",
    "print(People.country)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fn1\n"
     ]
    }
   ],
   "source": [
    "p.fn1()  # 会执行实例方法还是类方法呢"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fn1 静态方法\n"
     ]
    }
   ],
   "source": [
    "People.fn1()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "<br/>\n",
    "类的静态方法中无法调用任何类属性和类方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CLanguage:\n",
    "    country = 'china'\n",
    "    \n",
    "    #类构造方法，也属于实例方法\n",
    "    def __init__(self):\n",
    "        self.name = \"C语言中文网\"\n",
    "        self.add = \"http://c.biancheng.net\"\n",
    "        \n",
    "    # 下面定义了一个say实例方法\n",
    "    def say(self):\n",
    "        print(\"正在调用 say() 实例方法\")\n",
    "        \n",
    "    @staticmethod\n",
    "    def run(a):\n",
    "        print(\"正在调用 run() 静态方法\")\n",
    "        # print(a.country)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "clang = CLanguage()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "正在调用 say() 实例方法\n"
     ]
    }
   ],
   "source": [
    "CLanguage.say(clang)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "正在调用 run() 静态方法\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'int' object has no attribute 'country'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-32-778394d0175f>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mCLanguage\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m#类的静态方法中无法调用任何类属性和类方法\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      2\u001b[0m \u001b[1;31m# CLanguage.run(clang)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-26-86b926da4a41>\u001b[0m in \u001b[0;36mrun\u001b[1;34m(a)\u001b[0m\n\u001b[0;32m     14\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mrun\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ma\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     15\u001b[0m         \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"正在调用 run() 静态方法\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 16\u001b[1;33m         \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ma\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcountry\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: 'int' object has no attribute 'country'"
     ]
    }
   ],
   "source": [
    "CLanguage.run(1) #类的静态方法中无法调用任何类属性和类方法\n",
    "# CLanguage.run(clang)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## python中的多态, 由于python本身就是动态绑定，天然具有多态性质"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Animal(object):\n",
    "    def run(self):\n",
    "        print('Animal is running...')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Dog(Animal):\n",
    "     def run(self):\n",
    "        print('Dog is running...')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dog is running...\n"
     ]
    }
   ],
   "source": [
    "dog = Dog()\n",
    "dog.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dog is running...\n"
     ]
    }
   ],
   "source": [
    "def Duotai(Animal):\n",
    "    Animal.run()\n",
    "Duotai(dog)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Animal is running...\n"
     ]
    }
   ],
   "source": [
    "ani = Animal()\n",
    "ani.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Animal:\n",
    "    def run(self):\n",
    "        raise AttributeError('子类必须实现这个方法')\n",
    "        \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": 66,
   "metadata": {},
   "outputs": [],
   "source": [
    "peo1=People()\n",
    "pig1=Pig()\n",
    "d1=Dog()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "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": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [],
   "source": [
    "import abc\n",
    "class Animal(metaclass=abc.ABCMeta): #同一类事物:动物\n",
    "    @abc.abstractmethod\n",
    "    def talk(self):\n",
    "        pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [],
   "source": [
    "class People(Animal): #动物的形态之一:人\n",
    "    def talk(self):\n",
    "        print('say hello')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Dog(Animal): #动物的形态之二:狗\n",
    "    def talk(self):\n",
    "        print('say wangwang')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Pig(Animal): #动物的形态之三:猪\n",
    "    def talk(self):\n",
    "        print('say aoao')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "文件有多种形态：文件、文本文件、可执行文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "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": {},
   "outputs": [],
   "source": [
    "class Text(File): #文件的形态之一:文本文件\n",
    "    def click(self):\n",
    "        print('open file')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "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": 73,
   "metadata": {},
   "outputs": [],
   "source": [
    "#多态性：一种调用方式，不同的执行效果（多态性）\n",
    "def func(obj):\n",
    "    obj.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "人正在走\n",
      "pig is walking\n",
      "dog is running\n"
     ]
    }
   ],
   "source": [
    "func(peo1)\n",
    "func(pig1)\n",
    "func(d1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "人正在走\n",
      "pig is walking\n"
     ]
    }
   ],
   "source": [
    "peo1.run()\n",
    "pig1.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 多态性依赖于：继承\n",
    "##多态性：定义统一的接口，\n",
    "def func(obj): #obj这个参数没有类型限制，可以传入不同类型的值\n",
    "    obj.run() #调用的逻辑都一样，执行的结果却不一样"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "人正在走\n",
      "pig is walking\n",
      "dog is running\n"
     ]
    }
   ],
   "source": [
    "func(peo1)\n",
    "func(pig1)\n",
    "func(d1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [],
   "source": [
    "def func(animal): #参数animal就是对态性的体现\n",
    "    animal.talk()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "say hello\n"
     ]
    }
   ],
   "source": [
    "people1=People() #产生一个人的对象\n",
    "pig1=Pig() #产生一个猪的对象\n",
    "dog1=Dog() #产生一个狗的对象\n",
    "func(people1) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "say aoao\n"
     ]
    }
   ],
   "source": [
    "func(pig1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "say wangwang\n"
     ]
    }
   ],
   "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": {},
   "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": 1,
   "metadata": {},
   "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的功能，<br/>\n",
    "**定义好Runnable和Flyable的类,在java里面是接口：**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "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": "markdown",
   "metadata": {},
   "source": [
    "对于需要Runnable功能的动物，就多继承一个Runnable，例如Dog："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Running...\n"
     ]
    }
   ],
   "source": [
    "class Dog(Mammal, Runnable):\n",
    "    pass\n",
    "dog1 = Dog()\n",
    "dog1.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "float"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(3.14)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过**type()函数**创建类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fn1(self, name='dog'): # 单独定义成员函数\n",
    "    print('Hello, %s.' % name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用type（）创建class，显示名称Dog_1, 继承(Mammal,Runnable)，使用字典传递函数，并命名为hello\n",
    "Dog1 = type('Dog_1', (Mammal,Runnable), dict(hello=fn1)) \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class '__main__.Dog_1'>\n",
      "Running...\n",
      "Hello, dog.\n"
     ]
    }
   ],
   "source": [
    "d2 = Dog1()\n",
    "print(Dog1)\n",
    "d2.run()\n",
    "d2.hello()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用元类\n",
    "\n",
    "\n",
    "**type()**\n",
    "\n",
    "动态语言和静态语言最大的不同，就是**函数和类的定义，不是编译时定义的，而是运行时动态创建的**。\n",
    "\n",
    "比方说我们要定义一个Hello的class，就写一个hello.py模块："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "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": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, world.\n"
     ]
    }
   ],
   "source": [
    "h = Hello()\n",
    "h.hello()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'type'>\n"
     ]
    }
   ],
   "source": [
    "print(type(Hello))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class '__main__.Hello'>\n"
     ]
    }
   ],
   "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": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fn(self, name='world'): # 先定义函数\n",
    "    print('Hello, %s.' % name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用type（）创建Hello class, 并把函数送入类中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "ello = type('Hello', (object,), dict(hello=fn))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, world.\n"
     ]
    }
   ],
   "source": [
    "h = ello()\n",
    "h.hello()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'type'>\n",
      "<class '__main__.Hello'>\n"
     ]
    }
   ],
   "source": [
    "print(type(ello))\n",
    "print(type(h))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "要创建一个class对象，type()函数依次传入3个参数：\n",
    "\n",
    "class的名称；\n",
    "继承的父类集合，注意Python支持多重继承，如果只有一个父类，别忘了tuple的单元素写法；\n",
    "class的方法名称与函数绑定，这里我们把函数fn绑定到方法名hello上。\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": 18,
   "metadata": {},
   "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": 19,
   "metadata": {},
   "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": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1]"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "L = MyList()\n",
    "L.add(1)\n",
    "L"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'list' object has no attribute 'add'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-21-77283c537e1c>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# 而普通的list没有add()方法：\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[0mL2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mlist\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mL2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: 'list' object has no attribute 'add'"
     ]
    }
   ],
   "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": {},
   "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": {},
   "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": {},
   "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": {},
   "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": {},
   "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": {},
   "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": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyClass:\n",
    "    \"\"\"一个简单的类实例\"\"\"\n",
    "    i = 12345\n",
    "    def f(self):\n",
    "        return 'hello world'\n",
    " \n",
    "# 实例化类\n",
    "x = MyClass()\n",
    "y= MyClass()\n",
    "# 访问类的属性和方法\n",
    "print(\"MyClass 类的属性 i 为：\", x.i)\n",
    "print(\"MyClass 类的方法 f 输出为：\", x.f())\n",
    "y.i=222\n",
    "print(MyClass.i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class People:\n",
    "    #定义基本属性\n",
    "    name = ''\n",
    "    age = 0\n",
    "    #定义私有属性,私有属性在类外部无法直接进行访问\n",
    "    __weight = 0\n",
    "    #定义构造方法\n",
    "    def __init__(self,n,a,w):\n",
    "        self.name = n\n",
    "        self.age = a\n",
    "        self.__weight = w\n",
    "    def speak(self):\n",
    "        print(\"%s 说: 我 %d 岁。\" %(self.name,self.age))\n",
    " \n",
    "# 实例化类\n",
    "p = People('runoob',10,30)\n",
    "p.speak()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p.age"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "People.age"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python面向对象中super用法与MRO机制\n",
    "\n",
    "https://www.cnblogs.com/chenhuabin/p/10058594.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "调用子类方法\n",
      "调用父类方法\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "class Parent:        # 定义父类\n",
    "   def myMethod(self):\n",
    "      print ('调用父类方法')\n",
    " \n",
    "class Child(Parent): # 定义子类\n",
    "   def myMethod(self):\n",
    "      print ('调用子类方法')\n",
    " \n",
    "c = Child()          # 子类实例\n",
    "c.myMethod()         # 子类调用重写方法\n",
    "super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法\n",
    "# Parent.myMehod()\n",
    "print('...')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "d1\n",
      "aaa\n",
      "ddddd\n"
     ]
    }
   ],
   "source": [
    "class A:\n",
    "    pass\n",
    "\n",
    "class D:\n",
    "    def __init__(self): \n",
    "        print(self.d1)\n",
    "        print('aaa')\n",
    "        \n",
    "class DeepLabHead(D):\n",
    "    d1 = 'd1'\n",
    "    def __init__(self,num_c1,num_c2):\n",
    "        super(DeepLabHead,self).__init__()\n",
    "        print('ddddd')\n",
    "dd = DeepLabHead(1,2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Base:\n",
    "    def __init__(self):\n",
    "        print('Base.__init__')\n",
    "\n",
    "class A(Base):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        print('A.__init__')\n",
    "\n",
    "class B(Base):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        print('B.__init__')\n",
    "\n",
    "class C(Base):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        print('C.__init__')\n",
    "\n",
    "class D(A, B, C):\n",
    "    def __init__(self):\n",
    "        super().__init__()  # 等同于 super(D, self).__init__()\n",
    "        print('D.__init__')\n",
    "\n",
    "D()\n",
    "print(D.mro())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Base:\n",
    "    def __init__(self):\n",
    "        print('Base.__init__')\n",
    "\n",
    "class A(Base):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        print('A.__init__')\n",
    "\n",
    "class B(Base):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        print('B.__init__')\n",
    "\n",
    "class D(A, B):\n",
    "    def __init__(self):\n",
    "        super(B).__init__()  # 值传递一个参数\n",
    "        print('D.__init__')\n",
    "\n",
    "D()\n",
    "print(D.mro())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Base:\n",
    "    def __init__(self):\n",
    "        print('Base.__init__')\n",
    "\n",
    "class A(Base):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        print('A.__init__')\n",
    "\n",
    "class B(Base):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        print('B.__init__')\n",
    "\n",
    "class D(A, B):\n",
    "    def __init__(self):\n",
    "        super(B, self).__init__()  # self是B的子类D的实例\n",
    "        print('D.__init__')\n",
    "\n",
    "D()\n",
    "print(D.mro())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class A:\n",
    "    def fun(self):\n",
    "        print('A.fun')\n",
    "\n",
    "class B(A):\n",
    "    def fun(self):\n",
    "        super(B , self).fun()\n",
    "        print('B.fun')\n",
    "\n",
    "class C(A):\n",
    "    def fun(self):\n",
    "        super(C , self).fun()\n",
    "        print('C.fun')\n",
    "\n",
    "class D(B , C):\n",
    "    def fun(self):\n",
    "        super(D , self).fun()\n",
    "        print('D.fun')\n",
    "\n",
    "D().fun()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "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.6.13"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "253px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
