{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d9cb6bfb",
   "metadata": {},
   "source": [
    "# 继承与复用"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "231a0b83",
   "metadata": {},
   "source": [
    "在自定义类型的基本形式中:\n",
    "\n",
    "```python\n",
    "class ClassName(ParentClass):\n",
    "    \"\"\"class docstring\"\"\"\n",
    "    def some_method(self, ...):\n",
    "        return ...\n",
    "```\n",
    "\n",
    "ParentClass是用来进行继承的,被继承的ParentClass是父类,定义的ClassName是子类。可以认为子类是一种特殊的父类。\n",
    "\n",
    "例如,假设父类是哺乳动物,人作为一个子类可以继承这个父类,因为人是哺乳动物的一种;狮子也可以继承哺乳动物,因为狮子也是哺乳动物的一种。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "4610fc79",
   "metadata": {},
   "source": [
    "## 类的继承"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "635c7cab",
   "metadata": {},
   "source": [
    "考虑这样一个表示树叶的类:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a36e7da9",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Leaf(object):\n",
    "    def __init__(self, color='green'):\n",
    "        self.color = color\n",
    "\n",
    "    def fall(self, season=\"autumn\"):\n",
    "        print(f\"A leaf falls in {season}!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b3a7c490",
   "metadata": {},
   "source": [
    "继承这个类,生成一个枫树叶类:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "8fd3dae4",
   "metadata": {},
   "outputs": [],
   "source": [
    "class MapleLeaf(Leaf):\n",
    "    def change_color(self):\n",
    "        if self.color == \"green\":\n",
    "            self.color = \"red\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "013464f5",
   "metadata": {},
   "source": [
    "构造一个子类对象:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c2ce6df7",
   "metadata": {},
   "outputs": [],
   "source": [
    "mleaf = MapleLeaf()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "9c71f8cb",
   "metadata": {},
   "source": [
    "子类会继承父类的属性和方法,父类的属性和方法可以直接调用:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "29d73263",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A leaf falls in autumn!\n"
     ]
    }
   ],
   "source": [
    "mleaf.fall()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "426c68dd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'green'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mleaf.color"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c33456b6",
   "metadata": {},
   "source": [
    "子类虽然没有定义构造函数,但是会直接继承父类的构造函数:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c2b42098",
   "metadata": {},
   "outputs": [],
   "source": [
    "mleaf2 = MapleLeaf(\"orange\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "e40ef349",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'orange'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mleaf2.color"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec403e0f",
   "metadata": {},
   "source": [
    "子类额外定义的方法:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "2d213cb8",
   "metadata": {},
   "outputs": [],
   "source": [
    "mleaf.change_color()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "3bb2fa10",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'red'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mleaf.color"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44289e50",
   "metadata": {},
   "source": [
    "## 方法的重载"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ee37ba6",
   "metadata": {},
   "source": [
    "子类可以对父类中已有的方法进行重载。例如,在枫树叶类中对`.fall()`方法进行重载,即重新定义:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "9686c9a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "class MapleLeaf(Leaf):\n",
    "    def change_color(self):\n",
    "        if self.color == \"green\":\n",
    "            self.color = \"red\"\n",
    "    \n",
    "    def fall(self, season=\"autumn\"):\n",
    "        self.change_color()\n",
    "        print(f\"A leaf falls in {season}!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "927dded2",
   "metadata": {},
   "source": [
    "在这个例子中,`.fall()`方法被重载,并调用了自定义类中的已有方法。方法定义中的第一个参数`self`表示的就是对象自身,所以可以用`self.change_color()`实现对已有方法的调用:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "7061f8cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "mleaf = MapleLeaf()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "364a7a02",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'green'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mleaf.color"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "153090d1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A leaf falls in autumn!\n"
     ]
    }
   ],
   "source": [
    "mleaf.fall()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "865ab7c1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'red'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mleaf.color"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9fe2191",
   "metadata": {},
   "source": [
    "## super()函数"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "12781a14",
   "metadata": {},
   "source": [
    "与父类的.fall()方法相比,子类的方法只增加了.change_color()的调用,之后的操作与父类的.fall()方法一致,代码其实有冗余和浪费。Python提供了`super()`函数,在子类中调用父类的方法。具体定义如下:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "b99f05d4",
   "metadata": {},
   "outputs": [],
   "source": [
    "class MapleLeaf(Leaf):\n",
    "    def change_color(self):\n",
    "        if self.color == \"green\":\n",
    "            self.color = \"red\"\n",
    "    \n",
    "    def fall(self, season=\"autumn\"):\n",
    "        self.change_color()\n",
    "        super(MapleLeaf, self).fall(season)\n",
    "        # print(f\"A leaf falls in {season}!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13439014",
   "metadata": {},
   "source": [
    "能实现与上面一样的结果:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "131799e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "mleaf = MapleLeaf()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "ed6d7d2a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'green'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mleaf.color"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "aed3c77a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A leaf falls in autumn!\n"
     ]
    }
   ],
   "source": [
    "mleaf.fall()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "45fe2072",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'red'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mleaf.color"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "a6be393a",
   "metadata": {},
   "source": [
    "## 鸭子类型:一切都是为了复用\n",
    "\n",
    "鸭子类型(Duck Type)的概念来源于美国诗人詹姆斯·惠特科姆·莱利的诗句:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”在Python中,这个概念被衍生为:在使用对象时,可以不关注对象的类型,而关注对象具有的方法或属性;只要对象的属性和方法满足条件,就认为该对象是合法的。\n",
    "\n",
    "例如,定义这样的一个函数:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "bb2de45c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def something_fall(leaf):\n",
    "    leaf.fall()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1e0ef0c",
   "metadata": {},
   "source": [
    "这个函数接受一个参数leaf,并调用它的.fall()方法。Leaf类支持.fall()方法,因此该类型的对象是合法的:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "f22b737c",
   "metadata": {},
   "outputs": [],
   "source": [
    "leaf = Leaf()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "e097ca26",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A leaf falls in autumn!\n"
     ]
    }
   ],
   "source": [
    "something_fall(leaf)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "2ec867a8",
   "metadata": {},
   "source": [
    "子类MapleLeaf也支持.fall()方法,所以也是合法的对象:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "1ac9d7aa",
   "metadata": {},
   "outputs": [],
   "source": [
    "mleaf = MapleLeaf()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "6603faac",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A leaf falls in autumn!\n"
     ]
    }
   ],
   "source": [
    "something_fall(mleaf)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c1e85d42",
   "metadata": {},
   "source": [
    "再定义一个类苹果:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "0e90ed20",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Apple(object):\n",
    "    def fall(self):\n",
    "        print(\"An apple falls!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "62d3a582",
   "metadata": {},
   "outputs": [],
   "source": [
    "apple = Apple()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "f61690f0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "An apple falls!\n"
     ]
    }
   ],
   "source": [
    "something_fall(apple)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "244ac641",
   "metadata": {},
   "source": [
    "在鸭子类型机制下,Python将函数和方法中的类型检查,变成了接口检查的模式,即something_fall()函数不会检查传入的参数leaf是什么类型,而是检查leaf有没有实现.fall()接口。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "69b6fbe9",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.9.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}