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

多继承

上一章节我们讲到继承,子类继承父类,可以拥有父类的属性和方法,也可以进行扩展。但是有时候会发现,子类需要继承一个类的方法,又要继承另一个类的方法,才能完成要实现的功能。怎么办?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. Oracle 数据库 Database Express Edition 11g Release 2 (11.2) 错误解决集锦(使用语法)

    ORA-14552: 在查询或 DML 中无法执行 DDL, 提交或回退 PL/SQL“ORA-14551:无法在查询中执行DML操作 解决:在声明函数时加上: PRAGMA AUTONOMOUS_T ...

  2. 缓存的概念(反向代理、CDN)

    缓存在我们的日常开发中随处可见,理解缓存的概念,本质就是就近处理,比如很多热点数据,访问量很多,我们需要使用,就可以把它 缓存起来,然后下次访问就不用再去数据库的去查询了,而是直接使用缓存,现在说说大 ...

  3. Redis配置文件分析

    #Redis演示示例配置文件 # 注意单位问题:当须要设置内存大小的时候,能够使用类似1k.5GB.4M这种常见格式: # # 1k=> 1000 bytes #1kb => 1024 b ...

  4. 统计Oracle数据库文件的大小

    1. 统计数据文件.暂时文件.日志文件大小 select sum(bytes)/1024/1024/1024 as GB from dba_data_files; select sum(bytes)/ ...

  5. MYSQL 体系结构图-LRU FREELIST FLUSH LIST

  6. 查看linux系统状态

    就类似你装完xp后,或者你拿到一台新的机器的时候,你通常都是进入系统,看看他的cpu,内存,硬盘使用情况.我也按照这个来看看linux的系统状态.1:top 退出按q,这个就类似windows的任务管 ...

  7. Jquery小东西收集

    1. $(document).ready(),$(function(){}),$(window).load(),window.onload的关系与区别 $(document).ready(functi ...

  8. Canvas transform浅析

    没有前奏,直接进入主题 transform调用方法: ctx.transform(a,b,c,d,e,f);如下 var ctx = document.getElementById("myC ...

  9. Spring配置静态目录

    mvc-dispatcher-servlet.xml文件 <beans xmlns="http://www.springframework.org/schema/beans" ...

  10. CSS中表示cellpadding和cellspacing的方法

    本文和大家重点讨论一下用CSS来表示表格的cellpadding和cellspacing方法,表格的cellpadding和cellspacing我们经常会用一定的方式来清除默认样式,请看下文详细介绍 ...