从零开始学Python-Day40-继承和多态

面向对象编程过程中,我们可以从已有class继承,定义一个新的类class,这个类被称作子类Subclass,被继承者的类被称为基类、父类或者超类(Base class、Super class)。

例如我们编写了一个名为Animal的类:

>>> class Animal(object):

def run(self):

print('Animals are running...')

>>> animal = Animal()

>>> animal.run()

Animals are running...

当我们定义新的类Dog和Cat时,可以直接从Animal继承:

>>> class Dog(Animal):

pass


>>> class Cat(Animal):

pass


>>> dog = Dog()

>>> dog.run()

Animals are running...

>>> cat = Cat()

>>> cat.run()

Animals are running...

对于Dog和Cat,Animal就是它们的父类,它俩就是Animal的子类,都继承了Animal的run方法

当然可以对子类增加方法:

>>> class Dog(Animal):

def run(self):

print('Dog is running...')

def eat(self):

print('Dog is eating...')

相比直接从Animal继承的run,显然修改后的Dog类的run方法更符合逻辑。当子类和父类都存在相同方法run()时,子类的run覆盖了父类的run。

多态

当我们定义一个class时,实际上就是定义了一种数据类型,接下来我们看下面这组判断:

>>>a = list()

>>>b = Animal()

>>>c = Dog()

>>> isinstance(a, list)

True

>>> isinstance(b, Animal)

True

>>> isinstance(c, Dog)

True

>>> isinstance(c, Animal)

True

isinstance用来判断一个变量是否为某个类型,我们看到a,b,c都符合对应的类型;但是c除了对应Dog类型,同时也是Animal类型。

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

>>> b = Animal()

>>> isinstance(b, Dog)

False

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

>>> def run_twice(animal):

animal.run()

animal.run()


>>> run_twice(Animal())

Animals are running...

Animals are running...

>>> run_twice(Dog())

Dog is running...

Dog is running...

我们再定义一个Animal的子类Mouse:

>>> class Mouse(Animal):

def run(self):

print('Mouse is so small...')


>>> run_twice(Mouse())

Mouse is so small...

Mouse is so small...

可以看到对于新增的子类Mouse,不必修改run_twice,依赖父类Animal作为参数的函数或方法都可以不加修正的正常使用,原因就是多态!

多态的好处就在于此,我们要传入子类时,只要接收父类就可以,例如Dog、Cat都是Animal类型。

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

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

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

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

                ┌───────────────┐

                │    object    │

                └───────────────┘

                        │

          ┌────────────┴────────────┐

          │                        │

          ▼                        ▼

    ┌─────────────┐          ┌─────────────┐

    │  Animal    │          │    Plant    │

    └─────────────┘          └─────────────┘

          │                        │

    ┌─────┴──────┐            ┌─────┴──────┐

    │            │            │            │

    ▼            ▼            ▼            ▼

┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐

│  Dog  │  │  Cat  │  │  Tree  │  │ Flower  │

└─────────┘  └─────────┘  └─────────┘  └─────────┘

静态语言 vs 动态语言

对于静态语言(如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。

对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了:

class Timer(object):

    def run(self):

        print('Start...')

这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

Python的“file-like object“就是一种鸭子类型。对真正的文件对象,它有一个read()方法,返回其内容。但是,许多对象,只要有read()方法,都被视为“file-like object“。

许多函数接收的参数就是“file-like object“,你不一定要传入真正的文件对象,完全可以传入任何实现了read()方法的对象。

小结

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

动态语言的鸭子类型特点决定了继承不像静态语言那样是必须的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容

  • 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Sub...
    chen_000阅读 244评论 1 1
  • 程序在运行的过程中,根据传递的参数的不同,执行不同的函数或者操作不同的代码,这种在运行过程中才确定调用的方式成为运...
    云Shen不知处阅读 403评论 0 0
  • 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Sub...
    Cookie_hunter阅读 252评论 0 0
  • python学习笔记,特做记录,分享给大家,希望对大家有所帮助。 继承和多态 在OOP程序设计中,当我们定义一个c...
    Swift社区阅读 321评论 0 1
  • 今天也来写一个2017年总结。今天连赶了2场年饭后,终于发烧了。都不记得发烧是多少年的事情了,这回终于体会到,...
    御巢安王姗淇阅读 208评论 2 0