Python面向对象编程-02
Posted yangaoteng666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python面向对象编程-02相关的知识,希望对你有一定的参考价值。
本知识点参考廖雪峰的Python课程 [https://www.liaoxuefeng.com]
感谢北京图灵知非的免费课程 [http://www.tulingxueyuan.com/]
2018/6/26 星期二 11:15:57
继承和多态
- 继承就是一个类可以获得另外一个类中的成员属性和成员方法
- 作用: 减少代码,增加代码的复用功能, 同时可以设置类与类直接的关系
- 继承与被继承的概念:
- 被继承的类叫父类,也叫基类,也叫超类
- 用于继承的类,叫子类,也叫派生类
- 继承与被继承一定存在一个 is-a 关系
继承的语法:
class Animal(object): def run(self): print("Animal is runnung...") # Animal 继承于object,第一个类都继承于object,不管你写不写`object` class Dog(Animal): pass # Dog继承于Animal class Cat(Animal): pass # Cat继承于Animal
- 对于
Dog
来说,Animal
就是它的父类,对于Animal
来说,Dog
就是它的子类 继承的好处就在于子类获得了父类的全部功能。
Dog
也有了Animal
的Run()
方法>>> dog = Dog() # 子类一旦继承父类,则可以使用父类中除私有成员外的所有内容 >>> dog.run Animal is runnung...
我们对上面代码再次进行改进,给
Dog
和Cat
添加一些方法class Dog(Animal): def run(self): print(‘Dog is running...‘) class Cat(Animal): def run(self): print(‘Cat is running...‘)
运行:
>>> dog = Dog() >>> cat = Cat() >>> dog.run() >>> cat.run() 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这三种类型 但是:
>>> isinstance(c,Animal) True
- 看来c不仅仅是
Dog
,c还是Animal
!
不过仔细想想,这是有道理的,因为Dog
是从Animal
继承下来的,当我们创建了一个Dog
的实例c时,我们认为c的数据类型是Dog
没错,但c同时也是Animal
也没错,Dog
本来就是Animal的一种! 所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:
>>> b = Animal() >>> isinstance(b, Dog) False
要理解多态的好处,我们编写一个函数
def run_twice(animal): animal.run() animal.run()
当我们传入Animal的实例时,run_twice()就打印出:
>>> def run_twice(Animal()): Animal is running.. Animal is running..
当我们传入Dog的实例时,run_twice()就打印出:
>>> def run_twice(Dog()): Dog is running.. Dog is running..
当我们传入Cat的实例时,run_twice()就打印出:
>>> def 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()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:
- 对扩展开放:允许新增Animal子类;
- 对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
添加:
- super()
子类如果想扩充父类的方法,可以在定义新方法的同时访问父类成员来进行代码重用,可以使用 [父类名.父类成员] 的格式来调用父类成员,也可以使用super().父类成员的格式来调用。
class Animal(object): def run(self): print("Animal is runnung...") class Dog(Animal): def run(self): print(‘Dog is running...‘) class Cat(Animal): def run(self): super().run() print(‘Cat is running...‘)
- 继承变量函数的查找顺序问题
- 优先查找自己的变量
- 没有则查找父类
- 构造函数如果本类中没有定义,则自动查找调用父类构造函数
- 如果本类有定义,则不在继续向上查找
- 构造函数
- 是一类特殊的函数,在类进行实例化之前进行调用
- 如果定义了构造函数,则实例化时使用构造函数,不查找父类构造函数
- 如果没定义,则自动查找父类构造函数
- 如果子类没定义,父类的构造函数带参数,则构造对象时的参数应该按父类参数构造
多继承于重继承
- 继承面向对象编程的一个重要方式,通过继承,子类就可以扩展父类的功能
- 如果我们把我们能想到的动物进行分类
- Dog - 狗狗;
- Bat - 蝙蝠;
- Parrot - 鹦鹉;
- Ostrich - 鸵鸟
- 我们能飞的,能跑的,能游的,哺乳动物等分类,就太麻烦了,类的数量会指数级增长
我们正确的做法是采用多重继承,首先主要层次任然安装哺乳动物,和鸟类分:
class Animal(object): pass # 大类: class Mammal(Animal): pass class Bird(Animal): pass # 各种动物: class Dog(Mammal): pass class Bat(Mammal): pass class Parrot(Bird): pass class Ostrich(Bird): pass
然后,我们在给动物加上Runnable和Flyable的功能,只需要先定义好Runnable和Flyable的类:
class Runnable(object): def run(self): print(‘Running...‘) class Flyable(object): def fly(self): print(‘Flying...‘)
-对于需要Runnable功能的动物,就多继承一个Runnable,例如Dog:
class Dog(Mammal, Runnable): pass
对于需要Flyable功能的动物,就多继承一个Flyable,例如Bat:
class Bat(Mammal, Flyable): pass
通过多重继承,一个子类就可以同时获得多个父类的所有功能。
- Mixin
- Mixin设计模式
- 主要采用多继承方式对类的功能进行扩展
- Mixin概念
- MRO and Mixin
- Mixin模式
- Mixin MRO
- MRO
- 我们使用多继承语法来实现Minxin
- 使用Mixin实现多继承的时候非常小心
- 首先他必须表示某一单一功能,而不是某个物品
- 职责必须单一,如果由多个功能,则写多个Mixin
- Mixin不能依赖于子类的实现
- 子类及时没有继承这个Mixin类, 也能照样工作,只是缺少了某个功能
- 优点
- 使用Mixin可以在不对类进行任何修改的情况下,扩充功能
- 可以方便的组织和维护不同功能组件的划分
- 可以根据需要任意调整功能类的组合
- 可以避免创建很多新的类,导致类的继承混乱
以上是关于Python面向对象编程-02的主要内容,如果未能解决你的问题,请参考以下文章