参考链接: Python中的多态

文章目录

1、什么是多态“开闭”原则

2、静态语言 vs 动态语言小结

3、python中多态

1、什么是多态

要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个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

看来c不仅仅是Dog,c还是Animal!

不过仔细想想,这是有道理的,因为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,这些继承关系看上去就像一颗倒着的树。比如如下的继承树:

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

│    object     │

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

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

│                         │

▼                         ▼

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

│   Animal    │           │    Plant    │

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

│                         │

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

│            │            │            │

▼            ▼            ▼            ▼

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

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

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

2、静态语言 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()方法的对象。

小结

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

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

3、python中多态

类具有继承关系,并且子类类型可以向上转型看做父类类型,如果我们从 Person 派生出 Student和Teacher ,并都写了一个 whoAmI() 方法:

class Person(object):

def __init__(self, name, gender):

self.name = name

self.gender = gender

def whoAmI(self):

return 'I am a Person, my name is %s' % self.name

class Student(Person):

def __init__(self, name, gender, score):

super(Student, self).__init__(name, gender)

self.score = score

def whoAmI(self):

return 'I am a Student, my name is %s' % self.name

class Teacher(Person):

def __init__(self, name, gender, course):

super(Teacher, self).__init__(name, gender)

self.course = course

def whoAmI(self):

return 'I am a Teacher, my name is %s' % self.name

在一个函数中,如果我们接收一个变量 x,则无论该 x 是 Person、Student还是 Teacher,都可以正确打印出结果:

def who_am_i(x):

print x.whoAmI()

p = Person('Tim', 'Male')

s = Student('Bob', 'Male', 88)

t = Teacher('Alice', 'Female', 'English')

who_am_i(p)

who_am_i(s)

who_am_i(t)

运行结果:

I am a Person, my name is Tim

I am a Student, my name is Bob

I am a Teacher, my name is Alice

这种行为称为多态。 也就是说,方法调用将作用在 x 的实际类型上。

s 是Student类型,它实际上拥有自己的 whoAmI()方法以及从 Person继承的 whoAmI方法,但调用 s.whoAmI()总是先查找它自身的定义,如果没有定义,则顺着继承链向上查找,直到在某个父类中找到为止。

由于Python是动态语言,所以,传递给函数 who_am_i(x)的参数 x 不一定是 Person 或 Person 的子类型。任何数据类型的实例都可以,只要它有一个whoAmI()的方法即可:

class Book(object):

def whoAmI(self):

return 'I am a book'

这是动态语言和静态语言(例如Java)最大的差别之一。动态语言调用实例方法,不检查类型,只要方法存在,参数正确,就可以调用。

任务

Python提供了open()函数来打开一个磁盘文件,并返回 File 对象。File对象有一个read()方法可以读取文件内容:

例如,从文件读取内容并解析为JSON结果:

import json

f = open('/path/to/file.json', 'r')

print json.load(f)

由于Python的动态特性,json.load()并不一定要从一个File对象读取内容。任何对象,只要有read()方法,就称为File-like Object,都可以传给json.load()。

请尝试编写一个File-like Object, 把一个字符串 r'["Tim", "Bob", "Alice"]'包装成 File-like Object 并由 json.load() 解析。

CODE

只要为Students类加上 read()方法,就变成了一个File-like Object。

import json

class Students(object):

def __init__(self,):

self.name = r'["Tim", "Bob", "Alice"]'

def read(self):

return self.name

s = Students()

print json.load(s)

[转载] 【Python进阶】4-2 多态 | 什么是多态 / 静态语言vs动态语言 / python中多态相关推荐

  1. python是高级动态语言_Python动态语言之魅力揭秘

    之前的文章跟大家讲解了鸭子类型,其实鸭子类型是编程语言中动态类型语言中的一种设计风格.今天跟大家一起谈谈动态语言的魅力. 根据维基百科,动态编程语言是这样子定义的:动态编程语言是高级编程语言的一个类别 ...

  2. python进阶练习题:馏分类【难度:2级】--景越Python编程实例训练营,不同难度Python习题,适合自学Python的新手进阶

    python进阶练习题:馏分类[难度:2级]: 为您提供了类"分数",这两个参数(分子,分母)的骨架. 例: fraction1 =分数(4,5) 分数fraction1 =新分数 ...

  3. python进阶练习题:婴儿喜鹊【难度:2级】--景越Python编程实例训练营,不同难度Python习题,适合自学Python的新手进阶

    python进阶练习题:婴儿喜鹊[难度:2级]: 喜鹊是我最喜欢的鸟 婴儿的人更是这样- 这是一个鲜为人知的事实^宝宝喜鹊的黑白颜色相差** 至少** 一个地方** 最多** 从母亲喜鹊的颜色两个地方 ...

  4. 多态实现机制:静态分派和动态分派

    2019独角兽企业重金招聘Python工程师标准>>> 方法解析 Class文件的编译过程中不包含传统编译中的连接步骤,一切方法调用在Class文件里面存储的都只是符号引用,而不是方 ...

  5. 【C语言进阶深度学习记录】十六 静态库与动态库的创建与使用

    上一篇文章学习了编译的过程,点击链接查看:[C语言进阶深度学习记录]十五 编译过程简介,每一个C源文件编译后将会生成目标文件,那么这些目标文件,还需要链接起来,生成可执行文件. 文章目录 1 链接的意 ...

  6. python动态与静态语言_静态语言和动态语言的区别

    via https://blog.csdn.net/hard_days/article/details/84967298 今天在群里聊天的时候,谈论到python和Java相比居然不用定义变量类型.我 ...

  7. python 为什么动态语言_Python动态语言

    python 说Python是动态语言,是由于Python可以在代码运行中可以做更改,但是像C.Java之类的需要编译的语言,由于做过编译就不可以做修改了,所以是静态语言.但是像Python.PHP. ...

  8. python源码深度剖析_Python源码剖析——深度探索动态语言核心技术 | 学步园

    8.3  Python虚拟机的运行框架 当Python启动后,首先会进行Python运行时环境的 初始化.注意这里的运行时环境是一个与上一节剖析的执行环境不同的概念.运行时环境是一个全局的概念,而执行 ...

  9. python是静态语言还是动态语言_Python笔记--动/静态语言部分区别

    在学python之前一直把动态语言和静态语言的区别理解为要写int char这样的预定义类型的就是静态语言,而可以不用事先声明数据类型的则是动态语言,直到看到了这个: python是动态语言,实例创建 ...

最新文章

  1. explain性能分析
  2. winform 打印控件
  3. java $.class_java文件编译后额外生成的$1.class是怎么一回事
  4. 戛古 Kakku, Kekku-掸邦 shan state
  5. Eliminate Witches!【2011年北京赛区正赛赛题-2】
  6. java 事件监听应用_Spring Boot应用事件监听示例详解
  7. java 通用类型_Java获取通用类型的集合
  8. SpringBoot + MyBatis 之 Hello World
  9. 丢弃Git中的本地提交
  10. 物联网LoRa系列-2:LoRa系统架构与协议栈详解
  11. 矩阵乘法运算-JAVA实现
  12. 图扑软件基于钻孔数据的三维地质模型可视化
  13. ​Aruba 无线控制器本地账号登录密码重置
  14. 知识存储之Apache Jena
  15. python控制软件自动化测试,资讯详情-用python来使用Airtest 自动化工具-柠檬班-自动化测试-软件测试培训-自学官网...
  16. FFMPEG 播放 RTSP视频流
  17. 大数据三个特点的理解
  18. 编译原理8:递归下降分析器、扩充巴斯克范式、JavaCC
  19. python 3.8安装pillow包报错
  20. PhoneGap简介

热门文章

  1. 【NOIP2015】【Luogu2615】神奇的幻方(模拟填数)
  2. 路由器Lan、Wan短接问题
  3. armhf php环境搭建,armel、armhf 和 arm64 区别选择
  4. 华为系统移动数据连接到服务器,怎样设置手机数据连接到服务器配置
  5. java中包的概念及作用_Java中包的概念和使用实战
  6. 索佳电子水准数据传输软件_索佳全站仪数据传输软件
  7. 用yacc编写的算术运算计算器_10天学会四则运算小计算器设计之第5天
  8. 二叉搜索树第k小元素
  9. 8.26树状数组讲解
  10. [蓝桥杯]试题 基础练习 龟兔赛跑预测