zoukankan      html  css  js  c++  java
  • python学习第十六天 --继承进阶篇

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

    多继承

    上一章节我们讲到继承,子类继承父类,可以拥有父类的属性和方法,也可以进行扩展。但是有时候会发现,子类需要继承一个类的方法,又要继承另一个类的方法,才能完成要实现的功能。怎么办?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.新式类通过广度优先的方式查找属性。

  • 相关阅读:
    hdu-4283 You Are the One 区间dp,
    HDU
    HDU
    HDU
    SPOJ
    UESTC
    CodeForces
    HDU
    Git中文书籍
    zeng studio的项目窗口PHP Explorer
  • 原文地址:https://www.cnblogs.com/nx520zj/p/5750294.html
Copyright © 2011-2022 走看看