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

多继承

上一章节我们讲到继承,子类继承父类,可以拥有父类的属性和方法,也可以进行扩展。但是有时候会发现,子类需要继承一个类的方法,又要继承另一个类的方法,才能完成要实现的功能。怎么办?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. QTP自传之web常用对象

    随着科技的进步,“下载-安装-运行”这经典的三步曲已离我们远去.web应用的高速发展,改变了我们的思维和生活习惯,同时也使web方面的自动化测试越来越重要.今天,介绍一下我对web对象的识别,为以后的 ...

  2. hdu 1698 线段树成段更新

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1698 #include <cstdio> #include <cmath> # ...

  3. redis合库

    玩家数据全部保存在redis,对合服来绝对是个坑.因为一直都是做开发,合库这事还是第一次操作. 首先,合服要做哪些事情,当然不同的游戏肯定不一样.合服的目的是为了增加同个服务器上活跃玩家的数量.合服有 ...

  4. Mac OS X 程序员利器 – Homebrew安装与使用

    Mac OS X 程序员利器 – Homebrew安装与使用 Homebrew安装与使用 什么是Homebrew? Homebrew is the easiest and most flexible ...

  5. 理解Android的startservice和bindservice(转)

    一.首先,让我们确认下什么是service? service就是android系统中的服务,它有这么几个特点:它无法与用户直接进行交互.它必须由用户或者其他程序显式的启动.它的优先级比较高,它比处于前 ...

  6. c语言:蜗牛的爬行。

    main() { printf("hello,word!,第一次的c语言输出"); }

  7. POJ 2431 Expedition (STL 优先权队列)

    Expedition Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8053   Accepted: 2359 Descri ...

  8. 缓冲运动-1-[解决1].html

    <!DOCTYPE html> <html> <head lang="en">     <meta charset="UTF-8 ...

  9. MYSQL 体系结构图-LRU

  10. C# 邮件发送注意事项

    使用QQ邮箱作为smtp服务器时,遇到 "命令顺序不正确. 服务器响应为: AUTH first..",解决办法: smtpClient.UseDefaultCredentials ...