码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2016-08-08 19:12:05      阅读:243      评论:0      收藏:0      [点我收藏+]

标签:

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

多继承

上一章节我们讲到继承,子类继承父类,可以拥有父类的属性和方法,也可以进行扩展。但是有时候会发现,子类需要继承一个类的方法,又要继承另一个类的方法,才能完成要实现的功能。怎么办?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 最后为FatherA 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学习第十六天 --继承进阶篇

标签:

原文地址:http://www.cnblogs.com/nx520zj/p/5750294.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!