{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**面向对象编程**是最有效的软件编写方法之一。在面向对象编程中，\n",
    "你编写表示现实世界中的事物和情景的类，并基于这些类来创建对象。\n",
    "编写类时，你定义一大类对象都有的通用行为。基于类创建对象时，\n",
    "每个对象都自动具备这种通用行为，然后可根据需要赋予每个对象独\n",
    "特的个性。使用面向对象编程可模拟现实情景，其逼真程度达到了令\n",
    "你惊讶的地步"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 创建和使用类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用类几乎可以模拟任何东西。下面来编写一个表示小狗的简单类Dog——它表示的不是特\n",
    "定的小狗，而是任何小狗。对于大多数宠物狗，我们都知道些什么呢？它们都有名字和年龄；我\n",
    "们还知道，大多数小狗还会蹲下和打滚。由于大多数小狗都具备上述两项信息（名字和年龄）和\n",
    "两种行为（蹲下和打滚），我们的Dog类将包含它们。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**1 创建 Dog 类**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们定义了一个名为Dog的类。 根据约定，在Python中，首字母大写的名称指的是类。\n",
    "这个类定义中的括号是空的，因为我们要从空白创建这个类。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Dog():\n",
    "    \"\"\"一次模拟小狗的简单尝试\"\"\"\n",
    "    def __init__(self, name, age):\n",
    "        \"\"\"初始化属性name和age\"\"\"\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "    def sit(self):\n",
    "        \"\"\"模拟小狗被命令时蹲下\"\"\"\n",
    "        print(self.name.title() + \" is now sitting.\")\n",
    "    def roll_over(self):\n",
    "        \"\"\"模拟小狗被命令时打滚\"\"\"\n",
    "        print(self.name.title() + \" rolled over!\")\n",
    "        \n",
    "    def bark():\n",
    "        print('dog bark')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**方法__init__()**<br/>\n",
    "**类中的函数称为方法；**<br/>\n",
    "方法__init__()是一个特殊的方法，每当你根据Dog类创建新实例时， Python都会自动运行它。在这个方法的名称中，\n",
    "开头和末尾各有两个下划线，这是一种约定，旨在避免Python默认方法与普通方法发生名称冲突。\n",
    "\n",
    "这里的__init__()包含三个形参： self、 name和age。 在这个方法的定义中，形\n",
    "参self必不可少，还必须位于其他形参的前面。为何必须在方法定义中包含形参self呢？因为\n",
    "Python调用这个__init__()方法来创建Dog实例时， 将自动传入实参self。 \n",
    "\n",
    "每个与类相关联的方法调用都自动传递实参self，它是一个指向实例本身的引用，让实例能够访问类中的属性和方法。\n",
    "我们创建Dog实例时， Python将调用Dog类的方法__init__()。 我们将通过实参向Dog()传递名字和年龄； self会自动传递，\n",
    "因此我们不需要传递它。每当我们根据Dog类创建实例时，都只需给最后两个形参（ name和age）提供值。\n",
    "\n",
    "处定义的两个变量都有前缀self。以self为前缀的变量都可供类中的所有方法使用，我们\n",
    "还可以通过类的任何实例来访问这些变量。 self.name = name获取存储在形参name中的值，并将\n",
    "其存储到变量name中，然后该变量被关联到当前创建的实例。 self.age = age的作用与此类似。像这样可通过实例访问的变量称为属性。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**2 根据类创建实例**<br/>\n",
    "可将类视为有关如何创建实例的说明。 Dog类是一系列说明，让Python知道如何创建表示特\n",
    "定小狗的实例。\n",
    "\n",
    "下面来创建一个表示特定小狗的实例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "My dog's name is Willie.\n",
      "My dog is 6 years old.\n"
     ]
    }
   ],
   "source": [
    "my_dog = Dog('willie', 6)\n",
    "print(\"My dog's name is \" + my_dog.name.title() + \".\")\n",
    "print(\"My dog is \" + str(my_dog.age) + \" years old.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'self' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-7-8363b8724f3b>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mmy_dog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbark\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m: name 'self' is not defined"
     ]
    }
   ],
   "source": [
    "my_dog.bark()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dog bark\n"
     ]
    }
   ],
   "source": [
    "Dog.bark()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们让Python创建一条名字为'willie'、年龄为6的小狗。遇到这行代码时， Python使用实参'willie'和6调用Dog类中的方法__init__()。\n",
    "方法__init__()创建一个表示特定小狗的示例，并使用我们提供的值来设置属性name和age。方法\n",
    "__init__()并未显式地包含return语句，但Python自动返回一个表示这条小狗的实例。\n",
    "\n",
    "我们将这个实例存储在变量my_dog中。在这里，命名约定很有用：我们通常可以认为首字母大写的名称（如\n",
    "Dog）指的是类，而小写的名称（如my_dog）指的是根据类创建的实例。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**访问属性**<br/>\n",
    "要访问实例的属性，可使用句点表示法。在处，我们编写了如下代码来访问my_dog的属性name的值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'willie'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_dog.name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**调用方法**<br/>\n",
    "根据Dog类创建实例后，就可以使用句点表示法来调用Dog类中定义的任何方法。下面来让小\n",
    "狗蹲下和打滚："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Willie is now sitting.\n",
      "Willie rolled over!\n"
     ]
    }
   ],
   "source": [
    "my_dog = Dog('willie', 6)\n",
    "my_dog.sit()\n",
    "my_dog.roll_over()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**创建多个实例**<br/>\n",
    "可按需求根据类创建任意数量的实例。下面再创建一个名为your_dog的实例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "My dog's name is Willie.\n",
      "My dog is 6 years old.\n",
      "Willie is now sitting.\n",
      "\n",
      "Your dog's name is Lucy.\n",
      "Your dog is 3 years old.\n",
      "Lucy is now sitting.\n"
     ]
    }
   ],
   "source": [
    "my_dog = Dog('willie', 6)\n",
    "your_dog = Dog('lucy', 3)\n",
    "print(\"My dog's name is \" + my_dog.name.title() + \".\")\n",
    "print(\"My dog is \" + str(my_dog.age) + \" years old.\")\n",
    "my_dog.sit()\n",
    "\n",
    "print(\"\\nYour dog's name is \" + your_dog.name.title() + \".\")\n",
    "print(\"Your dog is \" + str(your_dog.age) + \" years old.\")\n",
    "your_dog.sit()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用类和实例\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**1 创建Car 类**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面来编写一个表示汽车的类，它存储了有关汽车的信息，还有一个汇总这些信息的方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Audi A4\n"
     ]
    }
   ],
   "source": [
    "class Car():\n",
    "    \"\"\"一次模拟汽车的简单尝试\"\"\"\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "my_new_car = Car('audi', 'a4', 2016)\n",
    "print(my_new_car.get_descriptive_name())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**2 给属性指定默认值**<br/>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "类中的每个属性都必须有初始值。在有些情况下，如设置默认值时，在方法__init__()内指定这种初始值是可行的；\n",
    "\n",
    "如果你对某个属性这样做了，就无需包含为它提供初始值的形参。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Audi A4\n",
      "This car has 0 miles on it.\n"
     ]
    }
   ],
   "source": [
    "class Car():\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    def read_odometer(self):\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "\n",
    "my_new_car = Car('audi', 'a4', 2016)\n",
    "print(my_new_car.get_descriptive_name())\n",
    "my_new_car.read_odometer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**3修改属性的值**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以以三种不同的方式修改属性的值：直接通过实例进行修改；通过方法进行设置；通过方\n",
    "法进行递增（增加特定的值）。下面依次介绍这些方法。<br/>\n",
    "**直接修改属性的值**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Audi A4\n"
     ]
    }
   ],
   "source": [
    "my_new_car = Car('audi', 'a4', 2016)\n",
    "print(my_new_car.get_descriptive_name())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "__main__.Car"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Car"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "my_new_car."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This car has 23 miles on it.\n"
     ]
    }
   ],
   "source": [
    "my_new_car.odometer_reading = 23\n",
    "my_new_car.read_odometer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**通过方法修改属性的值**<br/>\n",
    "如果有替你更新属性的方法，将大有裨益。这样，你就无需直接访问属性，而可将值传递给\n",
    "一个方法，由它在内部进行更新。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Car():\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    def read_odometer(self):\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "    def update_odometer(self, mileage):\n",
    "        \"\"\"将里程表读数设置为指定的值\"\"\"\n",
    "        self.odometer_reading = mileage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Audi A4\n",
      "This car has 0 miles on it.\n",
      "This car has 23 miles on it.\n"
     ]
    }
   ],
   "source": [
    "my_new_car = Car('audi', 'a4', 2016)\n",
    "print(my_new_car.get_descriptive_name())\n",
    "my_new_car.read_odometer()\n",
    "\n",
    "my_new_car.update_odometer(23)\n",
    "my_new_car.read_odometer()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Car():\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    def read_odometer(self):\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "    def update_odometer(self, mileage):\n",
    "        \"\"\"将里程表读数设置为指定的值\n",
    "        禁止将里程表读数往回调\"\"\"\n",
    "        if mileage >= self.odometer_reading:\n",
    "            self.odometer_reading = mileage\n",
    "        else:\n",
    "            print(\"You can't roll back an odometer!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**通过方法对属性的值进行递增**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有时候需要将属性值递增特定的量，而不是将其设置为全新的值。假设我们购买了一辆二手\n",
    "车，且从购买到登记期间增加了100英里的里程，下面的方法让我们能够传递这个增量，并相应\n",
    "地增加里程表读数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2013 Subaru Outback\n",
      "This car has 23500 miles on it.\n",
      "This car has 23600 miles on it.\n"
     ]
    }
   ],
   "source": [
    "class Car():\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    def read_odometer(self):\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")       \n",
    "    def increment_odometer(self, miles):\n",
    "        \"\"\"将里程表读数增加指定的量\"\"\"\n",
    "        self.odometer_reading += miles\n",
    "    def update_odometer(self, mileage):\n",
    "        \"\"\"将里程表读数设置为指定的值\n",
    "        禁止将里程表读数往回调\"\"\"\n",
    "        if mileage >= self.odometer_reading:\n",
    "            self.odometer_reading = mileage\n",
    "        else:\n",
    "            print(\"You can't roll back an odometer!\")\n",
    "\n",
    "            \n",
    "my_used_car = Car('subaru', 'outback', 2013)\n",
    "print(my_used_car.get_descriptive_name())\n",
    "my_used_car.update_odometer(23500)\n",
    "\n",
    "my_used_car.read_odometer()\n",
    "my_used_car.increment_odometer(100)\n",
    "my_used_car.read_odometer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 继承"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**1 子类的方法__init__()**<br/>\n",
    "\n",
    "创建子类的实例时， Python首先需要完成的任务是给父类的所有属性赋值。为此，子类的方\n",
    "法__init__()需要父类施以援手。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Car():\n",
    "    \"\"\"一次模拟汽车的简单尝试\"\"\"\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "        \n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    \n",
    "    def read_odometer(self):\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "        \n",
    "    def update_odometer(self, mileage):\n",
    "        if mileage >= self.odometer_reading:\n",
    "            self.odometer_reading = mileage\n",
    "        else:\n",
    "            print(\"You can't roll back an odometer!\")\n",
    "        \n",
    "    def increment_odometer(self, miles):\n",
    "        self.odometer_reading += miles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class ElectricCar(Car):\n",
    "    \"\"\"电动汽车的独特之处\"\"\"\n",
    "    def __init__(self, make, model, year):\n",
    "        super().__init__(make, model, year)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Tesla Model S\n"
     ]
    }
   ],
   "source": [
    "my_tesla = ElectricCar('tesla', 'model s', 2016)\n",
    "print(my_tesla.get_descriptive_name())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建子类时，父类必须包含在当前文件中，且位于子类前面。<br/>\n",
    "我们定义了子类ElectricCar。 定义子类时，必须在括号内指定父类的名称。<br/>\n",
    "方法__init__()接受创建Car实例所需的信息。\n",
    "\n",
    "super()是一个特殊函数，帮助Python将父类和子类关联起来。这行代码让Python调用ElectricCar<br/>\n",
    "的父类的方法__init__()，让ElectricCar实例包含父类的所有属性。父类也称为超类（ superclass），\n",
    "\n",
    "我们创建ElectricCar类的一个实例，并将其存储在变量my_tesla中。这行代码调用ElectricCar类中定义的<br/>\n",
    "方法__init__()，后者让Python调用父类Car中定义的方法__init__()。我们提供了实参'tesla'、 'model s'和2016。<br/>\n",
    "除方法__init__()外，电动汽车没有其他特有的属性和方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**2给子类定义属性和方法,定义继承的目的是为了扩展**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "让一个类继承另一个类后，可添加区分子类和父类所需的新属性和方法。\n",
    "下面来添加一个电动汽车特有的属性（电瓶），以及一个描述该属性的方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Car():\n",
    "    \"\"\"一次模拟汽车的简单尝试\"\"\"\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "        \n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    \n",
    "    def read_odometer(self):\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "        \n",
    "    def update_odometer(self, mileage):\n",
    "        if mileage >= self.odometer_reading:\n",
    "            self.odometer_reading = mileage\n",
    "        else:\n",
    "            print(\"You can't roll back an odometer!\")\n",
    "        \n",
    "    def increment_odometer(self, miles):\n",
    "        self.odometer_reading += miles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Tesla Model S\n",
      "This car has a 70-kWh battery.\n"
     ]
    }
   ],
   "source": [
    "class ElectricCar(Car):\n",
    "    \"\"\"Represent aspects of a car, specific to electric vehicles.\"\"\"\n",
    "    def __init__(self, make, model, year):\n",
    "        super().__init__(make, model, year)\n",
    "        self.battery_size = 70\n",
    "        \n",
    "    def describe_battery(self):\n",
    "        print(\"This car has a \" + str(self.battery_size) + \"-kWh battery.\")\n",
    "        \n",
    "my_tesla = ElectricCar('tesla', 'model s', 2016)\n",
    "print(my_tesla.get_descriptive_name())\n",
    "my_tesla.describe_battery()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**3重写父类的方法（覆盖）**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Car():\n",
    "    \"\"\"一次模拟汽车的简单尝试\"\"\"\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "        \n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    \n",
    "    def read_odometer(self):\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "        \n",
    "    def update_odometer(self, mileage):\n",
    "        if mileage >= self.odometer_reading:\n",
    "            self.odometer_reading = mileage\n",
    "        else:\n",
    "            print(\"You can't roll back an odometer!\")\n",
    "        \n",
    "    def increment_odometer(self, miles):\n",
    "        self.odometer_reading += miles\n",
    "        \n",
    "    def fill_gas_tank(self):\n",
    "        print('one tank')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "car = Car('audi', 'a4', 2016)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "one tank\n"
     ]
    }
   ],
   "source": [
    "car.fill_gas_tank()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class ElectricCar(Car):\n",
    "    def __init__(self, make, model, year):\n",
    "        super().__init__(make, model, year)\n",
    "        self.battery_size = 70\n",
    "     \n",
    "    # 覆盖父类Car的fill_gas_tank(self)方法\n",
    "    def fill_gas_tank(self):\n",
    "        print('ElectricCar have no tank')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ElectricCar have no tank\n"
     ]
    }
   ],
   "source": [
    "# 生成tesla\n",
    "my_tesla = ElectricCar('tesla', 'model-s', 2016)\n",
    "# 调用ElectriCar的fill_gas_tank方法\n",
    "my_tesla.fill_gas_tank()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**4将实例用作属性**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用代码模拟实物时，你可能会发现自己给类添加的细节越来越多：属性和方法清单以及文\n",
    "件都越来越长。在这种情况下，可能需要将类的一部分作为一个独立的类提取出来。你可以将大\n",
    "型类拆分成多个协同工作的小类。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Car():\n",
    "    \"\"\"一次模拟汽车的简单尝试\"\"\"\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "        \n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    \n",
    "    def read_odometer(self):\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "        \n",
    "    def update_odometer(self, mileage):\n",
    "        if mileage >= self.odometer_reading:\n",
    "            self.odometer_reading = mileage\n",
    "        else:\n",
    "            print(\"You can't roll back an odometer!\")\n",
    "        \n",
    "    def increment_odometer(self, miles):\n",
    "        self.odometer_reading += miles\n",
    "        \n",
    "    def fill_gas_tank(self):\n",
    "        print('one tank')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Battery():\n",
    "    \"\"\"一次模拟电动汽车电瓶的简单尝试\"\"\"\n",
    "    def __init__(self, battery_size=70):\n",
    "        self.battery_size = battery_size\n",
    "\n",
    "    def describe_battery(self):\n",
    "        print(\"This car has a \" + str(self.battery_size) + \"-kWh battery.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class ElectricCar(Car):\n",
    "    \"\"\"电动汽车的独特之处\"\"\"\n",
    "    def __init__(self, make, model, year):\n",
    "        super().__init__(make, model, year)\n",
    "        self.battery = Battery()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Tesla Model S\n",
      "This car has a 70-kWh battery.\n"
     ]
    }
   ],
   "source": [
    "my_tesla = ElectricCar('tesla', 'model s', 2016)\n",
    "print(my_tesla.get_descriptive_name())\n",
    "my_tesla.battery.describe_battery()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**在class Battery()中添加新方法**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid syntax (<ipython-input-38-f6f3233edf0a>, line 2)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;36m  File \u001b[1;32m\"<ipython-input-38-f6f3233edf0a>\"\u001b[1;36m, line \u001b[1;32m2\u001b[0m\n\u001b[1;33m    --snip--\u001b[0m\n\u001b[1;37m            ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n"
     ]
    }
   ],
   "source": [
    "class Car():\n",
    "    --snip--\n",
    "class Battery():\n",
    "    --snip--\n",
    "    def get_range(self):\n",
    "    \"\"\"打印一条消息，指出电瓶的续航里程\"\"\"\n",
    "        if self.battery_size == 70:\n",
    "            range = 240\n",
    "        elif self.battery_size == 85:\n",
    "            range = 270\n",
    "        message = \"This car can go approximately \" + str(range)\n",
    "        message += \" miles on a full charge.\"\n",
    "        print(message)\n",
    "\n",
    "class ElectricCar(Car):\n",
    "    --snip--\n",
    "    \n",
    "my_tesla = ElectricCar('tesla', 'model s', 2016)\n",
    "print(my_tesla.get_descriptive_name())\n",
    "my_tesla.battery.describe_battery()\n",
    "my_tesla.battery.get_range()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 导入类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**import**语句让Python打开模块car， 并导入其中的Car类。 这样我们就可以使用Car类了，\n",
    "就像它是在这个文件中定义的一样。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**1 导入单个类**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing car.py\n"
     ]
    }
   ],
   "source": [
    "%%writefile car.py\n",
    "class Car():\n",
    "    \"\"\"一次模拟汽车的简单尝试\"\"\"\n",
    "    # 初始化描述汽车的属性\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "        \n",
    "    #返回整洁的描述性名称\n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    \n",
    "    # 打印一条消息，指出汽车的里程\n",
    "    def read_odometer(self):\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "        \n",
    "    # 将里程表读数设置为指定的值拒绝将里程表往回拨\n",
    "    def update_odometer(self, mileage):\n",
    "        if mileage >= self.odometer_reading:\n",
    "            self.odometer_reading = mileage\n",
    "        else:\n",
    "            print(\"You can't roll back an odometer!\")\n",
    "            \n",
    "    # 将里程表读数增加指定的量\n",
    "    def increment_odometer(self, miles):\n",
    "        self.odometer_reading += miles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%%writefile my_car.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Audi A4\n",
      "This car has 23 miles on it.\n"
     ]
    }
   ],
   "source": [
    "from car import Car\n",
    "\n",
    "my_new_car = Car('audi', 'a4', 2016)\n",
    "print(my_new_car.get_descriptive_name())\n",
    "my_new_car.odometer_reading = 23\n",
    "my_new_car.read_odometer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**2 在一个模块中存储多个类**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "类Battery和ElectricCar都可帮助模拟汽车，因此下面将它们都加入模块car.py中："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing car1.py\n"
     ]
    }
   ],
   "source": [
    "%%writefile car1.py\n",
    "class Car():\n",
    "    \"\"\"一次模拟汽车的简单尝试\"\"\"\n",
    "    # 初始化描述汽车的属性\n",
    "    def __init__(self, make, model, year):\n",
    "        self.make = make\n",
    "        self.model = model\n",
    "        self.year = year\n",
    "        self.odometer_reading = 0\n",
    "        \n",
    "    #返回整洁的描述性名称\n",
    "    def get_descriptive_name(self):\n",
    "        long_name = str(self.year) + ' ' + self.make + ' ' + self.model\n",
    "        return long_name.title()\n",
    "    \n",
    "    # 打印一条消息，指出汽车的里程\n",
    "    def read_odometer(self):\n",
    "        print(\"This car has \" + str(self.odometer_reading) + \" miles on it.\")\n",
    "        \n",
    "    # 将里程表读数设置为指定的值拒绝将里程表往回拨\n",
    "    def update_odometer(self, mileage):\n",
    "        if mileage >= self.odometer_reading:\n",
    "            self.odometer_reading = mileage\n",
    "        else:\n",
    "            print(\"You can't roll back an odometer!\")\n",
    "            \n",
    "    # 将里程表读数增加指定的量\n",
    "    def increment_odometer(self, miles):\n",
    "        self.odometer_reading += miles\n",
    "        \n",
    "class Battery():\n",
    "    \"\"\"一次模拟电动汽车电瓶的简单尝试\"\"\"\n",
    "    #初始化电瓶的属性\n",
    "    def __init__(self, battery_size=60):\n",
    "        self.battery_size = battery_size\n",
    "        \n",
    "    #打印一条描述电瓶容量的消息\n",
    "    def describe_battery(self):\n",
    "        print(\"This car has a \" + str(self.battery_size) + \"-kWh battery.\")\n",
    "    \n",
    "    #打印一条描述电瓶续航里程的消息\n",
    "    def get_range(self):\n",
    "        if self.battery_size == 70:\n",
    "            range = 240\n",
    "        elif self.battery_size == 85:\n",
    "            range = 270\n",
    "    message = \"This car can go approximately \" + str(range) + \" miles on a full charge.\"\n",
    "    print(message)\n",
    "    \n",
    "class ElectricCar(Car):\n",
    "    \"\"\"模拟电动汽车的独特之处\"\"\"\n",
    "    #初始化父类的属性，再初始化电动汽车特有的属性\n",
    "    def __init__(self, make, model, year):\n",
    "        super().__init__(make, model, year)\n",
    "        self.battery = Battery()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Tesla Model S\n",
      "This car has a 60-kWh battery.\n"
     ]
    }
   ],
   "source": [
    "from car1 import ElectricCar\n",
    "my_tesla = ElectricCar('tesla', 'model s', 2016)\n",
    "print(my_tesla.get_descriptive_name())\n",
    "my_tesla.battery.describe_battery()\n",
    "my_tesla.battery.get_range()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**3 从一个模块中导入多个类**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从一个模块中导入多个类时，用逗号分隔了各个类。导入必要的类后，就可根据需要\n",
    "创建每个类的任意数量的实例。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Volkswagen Beetle\n",
      "2016 Tesla Roadster\n"
     ]
    }
   ],
   "source": [
    "from car1 import Car, ElectricCar\n",
    "\n",
    "my_beetle = Car('volkswagen', 'beetle', 2016)\n",
    "print(my_beetle.get_descriptive_name())\n",
    "\n",
    "my_tesla = ElectricCar('tesla', 'roadster', 2016)\n",
    "print(my_tesla.get_descriptive_name())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在这个示例中，我们在处创建了一辆大众甲壳虫普通汽车，并在处创建了一辆特斯拉\n",
    "Roadster电动汽车："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**4 导入整个模块**<br/>\n",
    "你还可以导入整个模块，再使用句点表示法访问需要的类。这种导入方法很简单，代码也易\n",
    "于阅读。由于创建类实例的代码都包含模块名，因此不会与当前文件使用的任何名称发生冲突。\n",
    "下面的代码导入整个car模块，并创建一辆普通汽车和一辆电动汽车："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import car1 as a1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2016 Volkswagen Beetle\n",
      "2016 Tesla Roadster\n"
     ]
    }
   ],
   "source": [
    "my_beetle = a1.Car('volkswagen', 'beetle', 2016)\n",
    "print(my_beetle.get_descriptive_name())\n",
    "my_tesla = a1.ElectricCar('tesla', 'roadster', 2016)\n",
    "print(my_tesla.get_descriptive_name())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**5 导入模块中的所有类**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from car import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "正如你看到的，在组织大型项目的代码方面， Python提供了很多选项。熟悉所有这些选项很\n",
    "重要，这样你才能确定哪种项目组织方式是最佳的，并能理解别人开发的项目。\n",
    "一开始应让代码结构尽可能简单。先尽可能在一个文件中完成所有的工作，确定一切都能正确运行后，再将类移到独立的模块中。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Python 标准库**\n",
    "\n",
    "Python标准库是一组模块，安装的Python都包含它。你现在对类的工作原理已有大致的了解，\n",
    "可以开始使用其他程序员编写好的模块了。可使用标准库中的任何函数和类，为此只需在程序开\n",
    "头包含一条简单的import语句。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Jen's favorite language is Python.\n",
      "Sarah's favorite language is C.\n",
      "Edward's favorite language is Ruby.\n",
      "Phil's favorite language is Python.\n"
     ]
    }
   ],
   "source": [
    "from collections import OrderedDict\n",
    "\n",
    "favorite_languages = OrderedDict()\n",
    "favorite_languages['jen'] = 'python'\n",
    "favorite_languages['sarah'] = 'c'\n",
    "favorite_languages['edward'] = 'ruby'\n",
    "favorite_languages['phil'] = 'python' \n",
    "\n",
    "for name, language in favorite_languages.items():\n",
    "    print(name.title() + \"'s favorite language is \" + language.title() + \".\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有序字典兼具列表和字典的主要优点（在将信息关联起来的同时保留原来的顺序）。等你开始对关心的现实情形建模时，可能会发现有序字典正好能够满足需求。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "from random import randint\n",
    "x = randint(1, 6)\n",
    "print(x)"
   ]
  },
  {
   "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 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": 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
}
