这一章节主要讲解面向对象高级编程->继承进阶篇,包括类多继承介绍和继承经典类和新式类属性的查找顺序不同之处。

多继承

上一章节我们讲到继承,子类继承父类,可以拥有父类的属性和方法,也可以进行扩展。但是有时候会发现,子类需要继承一个类的方法,又要继承另一个类的方法,才能完成要实现的功能。怎么办?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学习第十六天 --继承进阶篇的更多相关文章

  1. python学习之路-5 基础进阶篇

    本篇涉及内容 双层装饰器字符串格式化 双层装饰器 装饰器基础请点我 有时候一个功能需要有2次认证的时候就需要用到双层装饰器了,下面我们来通过一个案例详细介绍一下双层装饰器: 执行顺序:自上而下 解释顺 ...

  2. python 学习笔记十一 SQLALchemy ORM(进阶篇)

    SqlAlchemy ORM SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据A ...

  3. Python学习记录之(五)-----类进阶篇

    静态方法 类方法 属性方法 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调 ...

  4. Python 学习第十六天 html 前端内容总结

    一,css知识总结 1, css属性 css的属性包括以下内容 position:规定元素的定位类型 background:属性在一个声明中设置所有的背景属性 可以设置的如下属性:   (1)back ...

  5. python学习笔记七 初识socket(进阶篇)

    socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...

  6. python学习第二十六天非固定参数几种情况

    python函数参数传递,位置参数,默认参数,关键词参数,最后介绍一个非固定参数,就可以向函数传递一个列表,元组,字典,具体看看用法 1,有一个* 号的参数情况 def goos_stu(id,*us ...

  7. python学习第十六天集合的关系测试

    在做数据分析的时候,要对一个集合分析,而且分析多个集合的之间的关系分析,那么用传统的循环的比较麻烦,集合提供很多方法,很容易比较多个集合的关系,并集,交集,差集,对称差集等. n1={1,2,4,6} ...

  8. Python 学习 第十篇 CMDB用户权限管理

    Python 学习 第十篇 CMDB用户权限管理 2016-10-10 16:29:17 标签: python 版权声明:原创作品,谢绝转载!否则将追究法律责任. 不管是什么系统,用户权限都是至关重要 ...

  9. Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G

    code&monkey   Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...

随机推荐

  1. a为整型数组,&a+1的含义

    #include <stdio.h> int main() { int a[10]; printf("a的值为:\t%d\n",a); printf("&am ...

  2. 浅谈层次化的AI架构

    原文地址:http://www.aisharing.com/archives/86/comment-page-1 记得在以前的一篇文章中谈到了一种类似于双缓冲的AI结构,最近在整理一些东西的时候,发现 ...

  3. 总结&计划

    最近完成的事儿: 1. 看完了<c专家编程>并且整理了读书笔记 2. 看了半章<大数据>发现这本书里面是纯纯的干货...习题需要认真做,算法需要仔细体会...不适合突击,尤其是 ...

  4. dependencyManagement与dependencies区别

    最近在阅读maven项目代码时,dependencyManagement与dependencies之间的区别不是很了解,现通过项目实例进行总结:项目epps-demob-pom下有一个模块是epps- ...

  5. GitLib

    http://www.360doc.com/content/15/0603/14/21631240_475362133.shtml 原文 http://blog.csdn.net/williamwan ...

  6. iOS中ASI和AFN的区别

    一.底层实现 1> AFN的底层基于OC的NSURLConnection和NSURLSession 2> ASI的底层基于纯C语言的CFNetwork框架 3> ASI的运行性能 高 ...

  7. Directx 3D编程实例:多个3D球的综合Directx实例

    最近朋友建议我写一些关于微软云技术的博客留给学校下一届的学生们看,怕下一届的MSTC断档.于是我也觉的有这个必要.写了几篇博客之后,我觉得也有必要把这一年的学习内容放在博客做个纪念,就这样写了本篇博客 ...

  8. 两个有序数组的第n大数

    两个有序数组,各自含有n个元素,求第n大的元素 1.顺序遍历两个数组,计数变量k统计出现的第k小元素,时间复杂度为O(n) 代码例如以下: int getmid(int a[],int b[],int ...

  9. Linux设备驱动编程之复杂设备驱动

    这里所说的复杂设备驱动涉及到PCI.USB.网络设备.块设备等(严格意义而言,这些设备在概念上并不并列,例如与块设备并列的是字符设备,而PCI.USB设备等都可能属于字符设备),这些设备的驱动中又涉及 ...

  10. ubuntu vim YouComlpeteMe配置

    使用vundle安装时,在.vimrc中添加 Plugin 'Valloric/YouCompleteMe' 使用Bundle会安装失败原因未知 YCM编译时附加选项--system-libclang ...