本章内容

    Python面向对象的多态和继承对比

=========================================

在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。

比如,我们已经编写了一个名为Animal的class,有一个run()方法可以直接打印:

class Animal(object):
def run(self):
print 'Animal is running...'

当我们需要编写Dog和Cat类时,就可以直接从Animal类继承:

class Dog(Animal):
pass class Cat(Animal):
pass

对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类。Cat和Dog类似。

继承有什么好处?最大的好处是子类获得了父类的全部功能。由于Animial实现了run()方法,因此,Dog和Cat作为它的子类,什么事也没干,就自动拥有了run()方法:

dog = Dog()
dog.run() cat = Cat()
cat.run()

运行结果如下:

Animal is running...
Animal is running...

当然,也可以对子类增加一些方法,比如Dog类:

class Dog(Animal):
def run(self):
print 'Dog is running...'
def eat(self):
print 'Eating meat...

继承的第二个好处需要我们对代码做一点改进。你看到了,无论是Dog还是Cat,它们run()的时候,显示的都是Animal is running...,符合逻辑的做法是分别显示Dog is running...和Cat is running...,因此,对Dog和Cat类改进如下:

class Dog(Animal):
def run(self):
print 'Dog is running...' class Cat(Animal):
def run(self):
print 'Cat is running...'

再次运行,结果如下:

Dog is running...
Cat is running...

当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。这样,我们就获得了继承的另一个好处:多态。

要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个class的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样:

a = list() # a是list类型
b = Animal() # b是Animal类型
c = Dog() # c是Dog类型

判断一个变量是否是某个类型可以用isinstance()判断:

>>> isinstance(a, list)
True
>>> isinstance(b, Animal)
True
>>> isinstance(c, Dog)
True

看来a、b、c确实对应着list、Animal、Dog这3种类型。

但是等等,试试:

>>> isinstance(c, Animal)
True

不过仔细想想,这是有道理的,因为Dog是从Animal继承下来的,当我们创建了一个Dog的实例c时,我们认为c的数据类型是Dog没错,但c同时也是Animal也没错,Dog本来就是Animal的一种!

所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:

>>> b = Animal()
>>> isinstance(b, Dog)
False

Dog可以看成Animal,但Animal不可以看成Dog。

要理解多态的好处,我们还需要再编写一个函数,这个函数接受一个Animal类型的变量:

def run_twice(animal):
animal.run()
animal.run()

当我们传入Animal的实例时,run_twice()就打印出:

>>> run_twice(Animal())
Animal is running...
Animal is running...

当我们传入Dog的实例时,run_twice()就打印出:

>>> run_twice(Dog())
Dog is running...
Dog is running...

当我们传入Cat的实例时,run_twice()就打印出:

>>> run_twice(Cat())
Cat is running...
Cat is running...

看上去没啥意思,但是仔细想想,现在,如果我们再定义一个Tortoise类型,也从Animal派生:

class Tortoise(Animal):
def run(self):
print 'Tortoise is running slowly...'

当我们调用run_twice()时,传入Tortoise的实例:

>>> run_twice(Tortoise())
Tortoise is running slowly...
Tortoise is running slowly...

你会发现,新增一个Animal的子类,不必对run_twice()做任何修改,实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。

多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:

对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:

对扩展开放:允许新增Animal子类;

对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。

继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。比如如下的继承树:

小结

继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写;

有了继承,才能有多态。在调用类实例方法的时候,尽量把变量视作父类类型,这样,所有子类类型都可以正常被接收;

Python3中,如果没有合适的类可以继承,就继承自object类。

Python入门之面向对象的多态和继承的更多相关文章

  1. Python入门之面向对象的多态

    本章目录: 一.多态 二.多态性 三.鸭子类型 ============================== 一.多态 多态指的是一类事物有多种形态. 动物有多种形态:人,狗,猪. import ab ...

  2. Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态)

    Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态) 1.面向对象的三大特性: (1)继承 ​ 继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,父类又可以 ...

  3. Python入门篇-面向对象概述

    Python入门篇-面向对象概述 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.语言的分类 面向机器 抽象成机器指令,机器容易理解 代表:汇编语言 面向过程 做一件事情,排出个 ...

  4. Python入门之面向对象的__init__和__new__方法

    Python入门之面向对象的__init__和__new__方法

  5. Python入门-初始面向对象

    之前我们代码基本上都是面向过程的,今天我们就来初始一下python中一个重要的内容:面向对象 一.面向对象和面向过程(重点理解) 1.面向过程: 一切以事物的流程为核心. 核心是"过程&qu ...

  6. python基础(24):面向对象三大特性一(继承)

    1. 继承 1.1 什么是继承 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类. python中类的继承分为:单继承和多继 ...

  7. Python入门之面向对象之类继承与派生

    本章内容 一.继承 二.抽象类 三.继承的实现原理 ======================================================= 一.继承 1. 继承的定义 继承是一 ...

  8. python之路----面向对象的多态特性

    多态 多态指的是一类事物有多种形态 动物有多种形态:人,狗,猪 import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.abstr ...

  9. Python入门之面向对象编程(一)面向对象概念及优点

    概念 谈到面向对象,很多程序员会抛出三个词:封装.继承和多态:或者说抽象.一切都是对象之类的话,然而这会让初学者更加疑惑.下面我想通过一个小例子来说明一下 面向对象一般是和面向过程做对比的,下面是一个 ...

随机推荐

  1. CodeForce 832A Sasha and Sticks

    A. Sasha and Sticks time limit per test2 seconds memory limit per test256 megabytes inputstandard in ...

  2. java 中常见的一些错误

    1.NosuchMethodError java 类中找不到该方法! 可能该类所在的同一个包下有一个相同的相同的类,然后那个类中没有我们所要调用的类. 解决方法:若那个类不需要,可以删除class! ...

  3. 1.0Tensorflow中出现编译问题的解决方案

    跑简单tf例程的时候遇到这个 sess = tf.Session(),I tensorflow/core/platform/cpu_feature_guard.cc:] Your CPU suppor ...

  4. javaScript高级教程(五) Event Flow

    1.两个阶段三个模型:Netscape支持事件捕获,IE支持事件冒泡,w3c是先捕获后冒泡 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 S ...

  5. sql server dba常用概念、操作分析char,varchar,nvarchar,varchar(max)

    1.设计表时如何使用char 与 varchar? 请写出你对varchar(max)的理解. 1.设计表时如何使用char 与 varchar? 请写出你对varchar(max)的理解. char ...

  6. mysql 权限管理 revoke 回收权限 命令

    回收所有库,所有表的所有权限 revoke all on *.* from 针对mike的账号 回收 所有库,所有表的select权限 mysql> revoke select on *.* f ...

  7. mysql 数据操作 多表查询 多表连接查询 外链接之左连接 右连接

    1.外链接之左连接:优先显示左表全部记录   left join 在内连接的基础上保留左表的记录 即便左表有一条记录和右表没有关系,也把他留下 mysql> select * from empl ...

  8. Selenium+Java元素定位之三

    首先自己先准备一个表格代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...

  9. oracle 之创建用户,表空间,授权,修改用户密码

    1.创建表空间 create tablespace ilinkcargoagent logging datafile 'D:\app\Administrator\oradata\ilinkcargoa ...

  10. 深入理解python之二——python列表和元组

    从一开始学习python的时候,很多人就听到的是元组和列表差不多,区别就是元组不可以改变,列表可以改变. 从数据结构来说,这两者都应当属于数组,元组属于静态的数组,而列表属于动态数组.稍后再内存的分配 ...