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

多继承

上一章节我们讲到继承,子类继承父类,可以拥有父类的属性和方法,也可以进行扩展。但是有时候会发现,子类需要继承一个类的方法,又要继承另一个类的方法,才能完成要实现的功能。怎么办?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. SRM 391(1-250pt)

    DIV1 250pt 题意:给两个'a'-'z'的字符串,是否存在一个'a'-'z'的置换,使得能将一个字符串转化成另一个字符串. 解法:题意即是求,s1和s2对应位置出现的字符在原字符串中出现的次数 ...

  2. Blue Jeans - POJ 3080(多串的共同子串)

    题目大意:有M个串,每个串的长度都是60,查找这M个串的最长公共子串(连续的),长度不能小于3,如果同等长度的有多个输出字典序最小的那个.   分析:因为串不多,而且比较短,所致直接暴力枚举的第一个串 ...

  3. 九度online judge 1543 二叉树

    题目1543:无限完全二叉树的层次遍历 时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:389 解决:54 题目描述: 有一棵无限完全二叉树,他的根节点是1/1,且任意一个节点p/q的左儿 ...

  4. Linux 安全

     Linux 安全 1.安装 使系统处于单独(或隔离)的网络中.以防止未受保护的系统连接到其它网络或互联网中受到可能的攻击 安装完成后将下面软件卸载 pump                      ...

  5. Ubuntu12.04安装hadoop

    1.      创建hadoop用户组和用户 a.  创建hadoop用户组 sudo addgroup hadoop b.  创建hadoop用户 sudo adduser –ingroup had ...

  6. 每天进步一点点——Linux

    http://blog.csdn.net/cywosp/article/category/443566/1

  7. 解决XCode 4.x SVN无法连接的问题

    XCode升级到4.X版本后,确实好用了不少.但普通都存在SVN无法连接的问题.XCode4.x Source Control功能迁移到了File - Source Control目录下,也出现了一些 ...

  8. c++回调编程本质

    1. boost:bind获得一个函数对象,就像函数指针一样,这个行为可以作为回调 2. bosot:bind的函数对象可以保存别的对象的引用,回调对象的成员函数 3. boost:function是 ...

  9. zoj 3537 Cake(区间dp)

    这道题目是经典的凸包的最优三角剖分,不过这个题目给的可能不是凸包,所以要提前判定一下是否为凸包,如果是凸包的话才能继续剖分,dp[i][j]表示已经排好序的凸包上的点i->j上被分割成一个个小三 ...

  10. HDU 1756 Cupid's Arrow 判断点在多边形的内部

    Cupid's Arrow Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...