python学习第十六天 --继承进阶篇

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

多继承

上一章节咱们讲到继承,子类继承父类,能够拥有父类的属性和方法,也能够进行扩展。可是有时候会发现,子类须要继承一个类的方法,又要继承另外一个类的方法,才能完成要实现的功能。怎么办?python给咱们提供了多继承的概念。相似于C++语言,俗称类的多继承。编程

看个例子:python3.x

>>> 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语言来说,继承能够分为单继承,多层继承,多重继承。spa

对于继承来说,子类若是有构造函数__init__,不会自动调用父类的构造函数。若是子类没有本身的构造函数__init__,则会直接从父类继承构造函数.code

>>> 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子类类型的实例,不然会报错:blog

TypeError: super(type, obj): obj must be an instance or subtype of type继承

针对多层继承来说,super的用法也是同样的。可是须要注意如下状况:get

>>> 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.新式类经过广度优先的方式查找属性。

相关文章
相关标签/搜索