{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python - Class Inheritance\n",
    "\n",
    "- https://openhome.cc/Gossip/Python/Inheritance.html\n",
    "- http://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p07_calling_method_on_parent_class.html\n",
    "- http://funhacks.net/explore-python/Class/super.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 理解 Python 中 `super()` 和 `__init__()` 方法\n",
    "\n",
    "`super()`的好處就是可以避免直接使用父類的名字.但是它主要用於多重繼承,[這裡面](http://www.artima.com/weblogs/viewpost.jsp?thread=236275)有很多好玩的東西.如果還不瞭解的話可以看看[官方文檔](https://docs.python.org/2/library/functions.html#super)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Base created\n",
      "Base created\n",
      "<__main__.ChildA object at 0x105a85dd8> <__main__.ChildB object at 0x105aa8080>\n"
     ]
    }
   ],
   "source": [
    "class Base(object):\n",
    "    def __init__(self):\n",
    "        print(\"Base created\")\n",
    "\n",
    "class ChildA(Base):\n",
    "    def __init__(self):\n",
    "        Base.__init__(self)\n",
    "\n",
    "class ChildB(Base):\n",
    "    def __init__(self):\n",
    "        super(ChildB, self).__init__()\n",
    "\n",
    "print(ChildA(), ChildB())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在Python中，可以進行多重繼承，這個時候要注意搜尋的順序，是從子類別開始，接著是同一階層父類別由左至右搜尋，再至更上層同一階層父類別由左 至右搜尋，直到達到頂層為止。例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "D.method4\n",
      "B.method3\n",
      "C.method2\n",
      "A.method1\n"
     ]
    }
   ],
   "source": [
    "class A(object):\n",
    "    def method1(self):\n",
    "        print('A.method1')\n",
    "    \n",
    "    def method2(self):\n",
    "        print('A.method2')\n",
    "\n",
    "class B(A):\n",
    "    def method3(self):\n",
    "        print('B.method3')\n",
    "\n",
    "class C(A):\n",
    "    def method2(self):\n",
    "        print('C.method2')\n",
    "    \n",
    "    def method3(self):\n",
    "        print('C.method3')\n",
    "\n",
    "class D(B, C):\n",
    "    def method4(self):\n",
    "        print('D.method4')\n",
    "\n",
    "        \n",
    "d = D()\n",
    "d.method4() # 在 D 找到，D.method4\n",
    "d.method3() # 以 D->B 順序找到，B.method3\n",
    "d.method2() # 以 D->B->C 順序找到，C.method2\n",
    "d.method1() # 以 D->B->C->A 順序找到，A.method1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Advanced Inheritance\n",
    "\n",
    "http://funhacks.net/explore-python/Class/super.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "class Base(object):\n",
    "    def __init__(self):\n",
    "        print(\"enter Base\")\n",
    "        print(\"leave Base\")\n",
    "\n",
    "class A(Base):\n",
    "    def __init__(self):\n",
    "        print(\"enter A\")\n",
    "        super(A, self).__init__()\n",
    "        print(\"leave A\")\n",
    "\n",
    "class B(Base):\n",
    "    def __init__(self):\n",
    "        print(\"enter B\")\n",
    "        super(B, self).__init__()\n",
    "        print(\"leave B\")\n",
    "\n",
    "class C(A, B):\n",
    "    def __init__(self):\n",
    "        print(\"enter C\")\n",
    "        super(C, self).__init__()\n",
    "        print(\"leave C\")\n",
    "```\n",
    "\n",
    "其中，Base 是父類，A, B 繼承自 Base, C 繼承自 A, B，它們的繼承關係是一個典型的『菱形繼承』，如下：\n",
    "\n",
    "```\n",
    "      Base\n",
    "      /  \\\n",
    "     /    \\\n",
    "    A      B\n",
    "     \\    /\n",
    "      \\  /\n",
    "       C\n",
    "```\n",
    "\n",
    "現在，讓我們看一下使用：\n",
    "\n",
    "```python\n",
    ">>> c = C()\n",
    "enter C\n",
    "enter A\n",
    "enter B\n",
    "enter Base\n",
    "leave Base\n",
    "leave B\n",
    "leave A\n",
    "leave C\n",
    "```\n",
    "\n",
    "如果你認為 `super` 代表『調用父類的方法』，那你很可能會疑惑為什麼 enter A 的下一句不是 enter Base 而是 enter B。原因是，**`super` 和父類沒有實質性的關聯**，現在讓我們搞清 `super` 是怎麼運作的。\n",
    "\n",
    "事實上，對於你定義的每一個類，Python 會計算出一個**方法解析順序（Method Resolution Order, MRO）列表**，**它代表了類繼承的順序**，我們可以使用下面的方式獲得某個類的 MRO 列表：\n",
    "\n",
    "```python\n",
    ">>> C.mro()   # or C.__mro__ or C().__class__.mro()\n",
    "[__main__.C, __main__.A, __main__.B, __main__.Base, object]\n",
    "```\n",
    "\n",
    "那這個 MRO 列表的順序是怎麼定的呢，它是通過一個 [C3 線性化算法](https://www.python.org/download/releases/2.3/mro/)來實現的，這裡我們就不去深究這個算法了，感興趣的讀者可以自己去瞭解一下，總的來說，一個類的 MRO 列表就是合併所有父類的 MRO 列表，並遵循以下三條原則：\n",
    "\n",
    "-   子類永遠在父類前面\n",
    "-   如果有多個父類，會根據它們在列表中的順序被檢查\n",
    "-   如果對下一個類存在兩個合法的選擇，選擇第一個父類\n",
    "\n",
    "當你使用 `super(cls, inst)` 時，Python 會在 inst 的 MRO 列表上搜索 cls 的下一個類。\n",
    "\n",
    "現在，讓我們回到前面的例子。\n",
    "\n",
    "首先看類 C 的 `__init__` 方法：\n",
    "\n",
    "```python\n",
    "super(C, self).__init__()\n",
    "```\n",
    "\n",
    "這裡的 self 是當前 C 的實例，self.**class**.mro() 結果是：\n",
    "\n",
    "```\n",
    "[__main__.C, __main__.A, __main__.B, __main__.Base, object]\n",
    "```\n",
    "\n",
    "可以看到，C 的下一個類是 A，於是，跳到了 A 的 `__init__`，這時會打印出 enter A，並執行下面一行代碼：\n",
    "\n",
    "```python\n",
    "super(A, self).__init__()\n",
    "```\n",
    "\n",
    "注意，這裡的 self 也是當前 C 的實例，MRO 列表跟上面是一樣的，搜索 A 在 MRO 中的下一個類，發現是 B，於是，跳到了 B 的 `__init__`，這時會打印出 enter B，而不是 enter Base。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "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.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
