博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

python 类 继承

Posted on 2015-07-10 17:13  bw_0927  阅读(237)  评论(0)    收藏  举报

在class语句内,任何赋值语句都会产生类属性。

 

在python中继承中的一些特点:

1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。有别于C#

2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数

3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

 

 

python和其他面向对象语言类似,每个类可以拥有一个或者多个父类,它们从父类那里继承了属性和方法。如果一个方法在子类的实例中被调用,或者一个属性在子类的实例中被访问,但是该方法或属性在子类中并不存在,那么就会自动的去其父类中进行查找。

如果子类和父类都有构造函数,子类其实是重写了父类的构造函数如果不显式调用父类构造函数,父类的构造函数就不会被执行,导致子类实例访问父类初始化方法中初始的变量就会出现问题。所有在子类中不调用父类的__init__的话,父类的属性和方法就

不会被继承到。

#!/usr/bin/python

class A:
    def __init__(self):
        self.namea = "aaa"

    def funca(self):
        print "function a : %s" % self.namea


class B(A):
    def __init__(self):
        self.nameb = "bbb"

    def funcb(self):
        print "function b : %s" % self.nameb


b=B()
print b.nameb
b.funcb()
#print b.namea            出错
#b.funca()              出错

  

在子类中,构造函数被重写,但新的构造方法没有任何关于初始化父类的属性和方法的代码,为了达到预期的效果,子类的构造方法必须调用其父类的构造方法来进行基本的初始化。

有两种方法能达到这个目的:

 

python面向对象中的继承关系中,子类对父类的构造方法的调用有两种方法:

  1. 父类名.__init__(self,参数)    #注意名字是父类    相当于c++中调用类的静态函数
  2. super(本子类名,self)__init__(其他参数)    #注意名字是本身子类,而且init后是self之外的参   

super()函数会返回一个super对象,这个对象负责进行方法解析,解析过程其会自动查找所有的父类以及父类的父类

方法一更直观,方法二可以一次性初始化所有超类

 

 

当存在继承关系的时候,有时候需要在子类中调用父类的方法,此时最简单的方法是把对象调用转换成类调用,需要注意的是这时self参数需要显式传递,例如:

>>> class FooParent:
        def bar(self, message):
            print(message)

>>> class FooChild(FooParent):
        def bar(self, message):
            FooParent.bar(self, message)

 

>>> FooChild().bar("Hello, World.")
Hello, World.

这样做有一些缺点,比如说如果修改了父类名称,那么在子类中会涉及多处修改,另外,Python是允许多继承的语言,如上所示的方法在多继承时就需要重复写多次,显得累赘。为了解决这些问题,Python引入了super()机制,例子代码如下:

>>> class FooParent:
        def bar(self, message):
            print(message)

        
>>> class FooChild(FooParent):
        def bar(self, message):
            super(FooChild, self).bar(message)

        
>>> FooChild().bar("Hello, World.")
Hello, World.

 

表面上看 super(FooChild, self).bar(message)方法和FooParent.bar(self, message)方法的结果是一致的,实际上这两种方法的内部处理机制大大不同,当涉及多继承情况时,就会表现出明显的差异来,直接给例子:

代码一:

class A:
    def __init__(self):
        print("Enter A")
        print("Leave A")

class B(A):
    def __init__(self):
        print("Enter B")
        A.__init__(self)
        print("Leave B")

class C(A):
    def __init__(self):
        print("Enter C")
        A.__init__(self)
        print("Leave C")

class D(A):
    def __init__(self):
        print("Enter D")
        A.__init__(self)
        print("Leave D")

class E(B, C, D):
    def __init__(self):
        print("Enter E")
        B.__init__(self)
        C.__init__(self)
        D.__init__(self)
        print("Leave E")

E()

结果:

Enter E
Enter B
Enter A
Leave A
Leave B
Enter C
Enter A
Leave A
Leave C
Enter D
Enter A
Leave A
Leave D
Leave E

执行顺序很好理解,唯一需要注意的是公共父类A被执行了多次。

代码二:

class A:
    def __init__(self):
        print("Enter A")
        print("Leave A")

class B(A):
    def __init__(self):
        print("Enter B")
        super(B, self).__init__()
        print("Leave B")

class C(A):
    def __init__(self):
        print("Enter C")
        super(C, self).__init__()
        print("Leave C")

class D(A):
    def __init__(self):
        print("Enter D")
        super(D, self).__init__()
        print("Leave D")

class E(B, C, D):
    def __init__(self):
        print("Enter E")
        super(E, self).__init__()
        print("Leave E")

E()

结果:

Enter E
Enter B
Enter C
Enter D
Enter A
Leave A
Leave D
Leave C
Leave B
Leave E

在super机制里可以保证公共父类仅被执行一次,至于执行的顺序,是按照mro进行的(E.__mro__)。