python学习第十六天 --继承进阶篇
这一章节主要讲解面向对象高级编程->继承进阶篇,包括类多继承介绍和继承经典类和新式类属性的查找顺序不同之处。
多继承
上一章节我们讲到继承,子类继承父类,可以拥有父类的属性和方法,也可以进行扩展。但是有时候会发现,子类需要继承一个类的方法,又要继承另一个类的方法,才能完成要实现的功能。怎么办?python给我们提供了多继承的概念。类似于C++语言,俗称类的多继承。
看个例子:
- >>> class Animal(object):
- def __init__(self,name):
- self.name = name
- >>> class Runable(object):
- pass
- >>> class Flyable(object):
- pass
- >>> class Dog(Animal,Runable):
- def __init__(self,name):
- super(Dog,self).__init__(name)
- >>> class Bird(Animal,Flyable):
- def __init__(self,name):
- super(Bird,self).__init__(name)
- >>> d = Dog('wangcai')
- >>> b = Bird('yingying')
声明了Animal类和Runable类,Flyable类。子类Dog因为即是动物,又具有run的能力。所以继承Animal类和Runable类。子类Bird因为即是动物,又具有fly的能力。所以继承Animal类和Runable类。
继承进阶
对于python语言来讲,继承可以分为单继承,多层继承,多重继承。
对于继承来讲,子类如果有构造函数__init__,不会自动调用父类的构造函数。如果子类没有自己的构造函数__init__,则会直接从父类继承构造函数.
- >>> class Person(object):
- def __init__(self):
- print('Person class initing!')
- >>> class Student(Person):
- def __init__(self):
- print('Student class initing!')
- >>> s = Student()
- Student class initing!//子类实例化对象s,并不会自动调用父类的__init__。(一定区别于C++,JAVA,C#一些面向对象语言)
如果一定需要用到父类的构造函数,则需要在子类的构造函数中显式的调用。
- >>> class Student(Person):
- def __init__(self):
- super(Student,self).__init__()
//调用了父类的__init__
//或者也可以写成 Person.__init__(self)- print('Student class initing!')
- >>> s = Student()
- Person class initing!
- Student class initing!
说明:super(type, obj),其中obj必须是type类型或者type子类类型的实例,否则会报错:
TypeError: super(type, obj): obj must be an instance or subtype of type
针对多层继承来讲,super的用法也是一样的。但是需要注意以下情况:
- >>> class Person(object):
- def __init__(self):
- print('Person class initing!')
- >>> class Man(Person):
- def __init__(self):
- super(Man,self).__init__()
- print('Man class initing!')
- >>> class Teenager(Man):
- def __init__(self):
- super(Teenager,self).__init__()
- print('Teenager class initing!')
- >>> class Student(Teenager):
- def __init__(self):
- super(Student,self).__init__()
- print('Student class initing!')
- >>> s = Student()
- Person class initing!
- Man class initing!
- Teenager class initing!
- Student class initing!
如果Student类,super(Student,self)改为super(Man,self)会有什么结果输出?
- >>> class Person(object):
- def __init__(self):
- print('Person class initing!')
- >>> class Man(Person):
- def __init__(self):
- super(Man,self).__init__()
- print('Man class initing!')
- >>> class Teenager(Man):
- def __init__(self):
- super(Teenager,self).__init__()
- print('Teenager class initing!')
- >>> class Student(Teenager):
- def __init__(self):
- super(Man,self).__init__()
- print('Student class initing!')
- >>> s = Student()
- Person class initing!
- Student class initing!
- class Student(Teenager):
- def __init__(self):
- super(Teenager,self).__init__()
- print('Student class initing!')
- >>> s = Student()
- Person class initing!
- Man class initing!
- Student class initing!
可看出super(type[,type2_or_obj]),type决定了super调用方法所在的父类--type的父类(如果有的话),即type决定了前往哪个父类调用指定的方法。
那么super(Man,self)指的是 调用Man类父类的Person类的__init__方法。
刚才在介绍继承的时候,说过如果子类并没有自己的__init__方法,则会继承父类的__init__。那么如果是多重继承的话,子类继承了两个甚至更多的类,那么子类是继承哪个类的__init__方法?
- >>> class FatherA(object):
- def __init__(self):
- print('FatherA class initing!')
- >>> class FatherB(object):
- def __init__(self):
- print('FatherB class initing!')
- >>> class Son(FatherA,FatherB):
- pass
- >>> s = Son()
- FatherA class initing!
将class Son(FatherA,FatherB)改为class Son(FatherB,FatherA)会有什么结果?
- >>> class Son(FatherB,FatherA):
- pass
- >>> s = Son()
- FatherB class initing!
大家可以通过上面的例子,可以发现:
子类从多个父类派生,子类没有自己的构造函数时,
(1)按继承顺序,第一个父类而它又有自己的构造函数,就继承它的构造函数;
(2)如果最前面第一个父类没有构造函数,则继承第2个的构造函数,如果第2个类也没有,则继承第3个的。以此类推,最后会继承object。
针对于构造函数__init__,遵循上面的继承规则。那么实例方法是否也遵循上面的继承规则?
- >>> class FatherA(object):
- def __init__(self):
- print('FatherA class initing!')
- def ft(self):
- print('FatherA ft fun!')
- >>> class FatherB(object):
- def __init__(self):
- print('FatherB class initing!')
- def ft(self,args):
- print('FatherB ft fun!')
- >>> class Son(FatherA,FatherB):
- def __init__(self):
- super(Son,self).ft()
- >>> s = Son()
- FatherA ft fun!
看起来实例方法也是遵循上面的规则,按继承顺序调用父类方法。
如果就是需要调用两个父类的ft方法怎么办?
- >>> class Son(FatherA,FatherB):
- def __init__(self):
- FatherA.ft(self)
- FatherB.ft(self,0)
- //显式调用
- >>> s =Son()
- FatherA ft fun!
- FatherB ft fun!
熟能生巧,来看看这个例子,能输出什么结果?
- >>> class FatherA(object):
- def __init__(self):
- print('FatherA class initing!')
- self.name = 'FatherA name'
- def get_name(self):
- return 'FatherA call '+ self.name
- >>> class FatherB(object):
- def __init__(self):
- print('FatherB class initing!')
- self.name = 'FatherB name'
- def get_name(self):
- return 'FatherB call '+ self.name
- >>> class Son(FatherA,FatherB):
- def __init__(self):
- FatherA.__init__(self)
- FatherB.__init__(self)
- print('Son class initing!')
- >>> s = Son()
- >>> s.get_name()
输出结果为:
- >>> s = Son()
- FatherA class initing!
- FatherB class initing!
- Son class initing!
- >>> s.get_name()
- 'FatherA call FatherB name'
解析:
(1)在Son类中,执行__init__函数,调用了FatherA.__init__(self),FatherB.__init__(self),所以self.name 最后为FatherB name。
(2)调用了s.get_name()方法,根据python多重继承规则,从左到右的继承顺序,调用的是FatherA的get_name方法。
继承经典类和新式类
何为经典类/新式类?
答:经典类是python2.2之前的东西,但是在2.7还在兼容,但是在3之后的版本就只承认新式类。新式类在python2.2之后的版本中都可以使用。
经典类/新式类区别?
答:经典类是默认没有派生自某个基类,而新式类是默认派生自object这个基类。
- //经典类
- class A():
- pass
- //新式类
- class A(object):
- pass
针对于经典类的多重继承采用的是深度优先继承.见例子:
- >>> class A():
- def f1(self):
- print('A f1')
- >>> class B(A):
- def f2(self):
- print('B f2')
- >>> class C(A):
- def f1(self):
- print('C f1')
- >>> class D(B,C):
- pass
- >>> d = D()
- >>> d.f1()
- A f1
解析:在访问d.f1()的时候,D这个类是没有f1方法。那么往上查找,先找到B,里面也没有,深度优先,访问A,找到了f1(),所以这时候调用的是A的f1(),从而导致C重写的f1()被绕过.
经典类在python3.x彻底被抛弃,在这里就不做过多的介绍。大家记得就好。上面的执行顺序:D->B->A
再来看看新式类:
- >>> class A(object):
- def f1(self):
- print('A-f1')
- >>> class B(object):
- def f1(self):
- print('B-f1')
- >>> class A(object):
- def f1(self):
- print('A-f1')
- >>> class B(object):
- def f1(self):
- print('B-f1')
- def bar(self):
- print('B-bar')
- >>> class C1(A,B):
- pass
- >>> class C2(A,B):
- def bar(self):
- print 'C2-bar'
- >>> class D(C1,C2):
- pass
- >>> d = D()
- >>> d.f1()
- A-f1
- >>> d.bar()
- C2-bar
从上面新式类的输出结果来看,新式类的搜索方式是采用“广度优先”的方式去查找属性。
实例d调用f1()时,搜索顺序是 D -> C1 -> C2 -> A
实例d调用bar()时,搜索顺序是 D -> C1 -> C2
归总python继承的特性:
1.子类如果有构造函数__init__,不会自动调用父类的构造函数。如果子类没有自己的构造函数__init__,则会直接从父类继承构造函数.如果一定需要用到父类的构造函数,则需要在子类的构造函数中显式的调用.
2.子类从多个父类派生,子类没有自己的构造函数时,
(1)按继承顺序,从左到右。第一个父类而它又有自己的构造函数,就继承它的构造函数;
(2)如果最前面第一个父类没有构造函数,则继承第2个的构造函数,如果第2个类也没有,则继承第3个的。以此类推,最后会继承object。
3.新式类通过广度优先的方式查找属性。
python学习第十六天 --继承进阶篇的更多相关文章
- python学习之路-5 基础进阶篇
本篇涉及内容 双层装饰器字符串格式化 双层装饰器 装饰器基础请点我 有时候一个功能需要有2次认证的时候就需要用到双层装饰器了,下面我们来通过一个案例详细介绍一下双层装饰器: 执行顺序:自上而下 解释顺 ...
- python 学习笔记十一 SQLALchemy ORM(进阶篇)
SqlAlchemy ORM SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据A ...
- Python学习记录之(五)-----类进阶篇
静态方法 类方法 属性方法 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调 ...
- Python 学习第十六天 html 前端内容总结
一,css知识总结 1, css属性 css的属性包括以下内容 position:规定元素的定位类型 background:属性在一个声明中设置所有的背景属性 可以设置的如下属性: (1)back ...
- python学习笔记七 初识socket(进阶篇)
socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...
- python学习第二十六天非固定参数几种情况
python函数参数传递,位置参数,默认参数,关键词参数,最后介绍一个非固定参数,就可以向函数传递一个列表,元组,字典,具体看看用法 1,有一个* 号的参数情况 def goos_stu(id,*us ...
- python学习第十六天集合的关系测试
在做数据分析的时候,要对一个集合分析,而且分析多个集合的之间的关系分析,那么用传统的循环的比较麻烦,集合提供很多方法,很容易比较多个集合的关系,并集,交集,差集,对称差集等. n1={1,2,4,6} ...
- Python 学习 第十篇 CMDB用户权限管理
Python 学习 第十篇 CMDB用户权限管理 2016-10-10 16:29:17 标签: python 版权声明:原创作品,谢绝转载!否则将追究法律责任. 不管是什么系统,用户权限都是至关重要 ...
- Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G
code&monkey Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...
随机推荐
- codevs2492 上帝造题的七分钟 2
2492 上帝造题的七分钟 2 题目描述 Description XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部. "第一分钟,X说,要有数列,于是便给定了一个正整数数列 ...
- segment
1.segmentedControlStyle 设置segment的显示样式. typedef NS_ENUM(NSInteger, UISegmentedControlStyle) { UISegm ...
- ASP.NET MVC3 ModelState.IsValid为false的问题
模型验证通常在submit后调用Action之前进行验证,eg: public class ZhengXing { [Key] public int ZhengXin ...
- scipy安装失败
pip install scipy安装失败 可以从uci网站下载wheel安装包然后执行pip install xx.whl进行安装 http://www.lfd.uci.edu/~gohlke/py ...
- angularJS 指令一
指令1.指令本质上就是AngularJS拓展具有自定义功能的HTML元素的途径.通过自定义元素来创建指令,如:<my-directive></my-directive>.dir ...
- 用canvas把图片变成黑白相片
<!--这里没有代码--> 原来是把灰度系数分别 乘以 每个像素点的三个像素色(R,G,B)的值,然后得到的三个值加起来,再把得到的值赋值进去给每个R ,G,B. 微软的MSDN上提到的是 ...
- ./filezilla: error while loading shared libraries: libpng12.so.0: cannot open shared object file: No such file or directory
opensuse系统 在filezilla官网下载压缩文件解压运行后报 ./filezilla: error while loading shared libraries: libpng12.so.0 ...
- 【算法与数据结构】在n个数中取第k大的数(基础篇)
(转载请注明出处:http://blog.csdn.net/buptgshengod) 题目介绍 在n个数中取第k大的数(基础篇),之所以叫基础篇是因为还有很多更高级的算法,这些 ...
- scrollview中停止滚动的监听
[补充]可以在主线程控制,特别注意 scrollView3.postDelayed(new Runnable() { @Override public void run() { scrollView3 ...
- iphone开发中数据持久化之——属性列表序列化(一)
数据持久化是应用程序开发过程中的一个基本问题,对应用程序中的数据进行持久化存储,有多重不同的形式.本系列文章将介绍在iphone开发过程中数据持久化的三种主要形式,分别是属性列表序列号.对象归档化以及 ...