zoukankan      html  css  js  c++  java
  • Python 类继承,__bases__, __mro__, super

    Python是面向对象的编程语言,也支持类继承。

    >>> class Base:

    ... pass

    ...

    >>> class Derived(Base):

    ... pass

      

    这样就定义了两个类,Derived继承了Base。issubclass(a,b)能够測试继承关系:

    >>> issubclass(Derived, Base)

    True

      

    在Python中,每一个类有一个__bases__属性,列出其基类

    >>> Derived.__bases__

    (<class '__main__.Base'>,)

      

    同C++,Python支持多重继承

    >>> class Derived2(Derived,Base):

    ... pass

    ...

    Derived2继承了Derived和Base(实际中不会这么写)

    >>> Derived2.__bases__

    (<class '__main__.Derived'>, <class '__main__.Base'>)

      

    这里,Derived,和Base的顺序不能搞反

    >>> class Derived2(Base, Derived):

    ... pass

    ...

    Traceback (most recent call last):

    File "<stdin>", line 1, in <module>

    TypeError: Cannot create a consistent method resolution

    order (MRO) for bases Derived, Base

      

    插一段C++

    C++代码

    class Base{

    };

      

    class Derived: public Base{

    };

      

    class Derived2: public Base, public Derived{

    };

      

    int main(){

    }

    mulit_inherit.cc:7:7: warning: direct base 'Base' inaccessible in 'Derived2' due to ambiguity [enabled by default]

    class Derived2: public Base, public Derived{

    ^

    mulit_inherit.cc:7:7: warning: direct base 'Base' inaccessible in 'Derived2' due to ambiguity [enabled by default]

    class Derived2: public Derived, public Base{

    ^

    能够见,C++并没有限制书写顺序。warning指示了Derrived2中不能訪问Base

    Derived2 d;

    Base &b = d;

    error: 'Base' is an ambiguous base of 'Derived2'

    Base &b = d;

    ^

      

    回到Python继承,Derived2是Derived的子类,也是Base的子类

    >>> issubclass(Derived2, Base)

    True

    >>> issubclass(Derived2, Derived)

    True

      

    __bases__类似于Javascript中Object对象的__proto__,是实现继承的基础,不同在于:__bases__不可改动,并且__bases__是类的属性而不是对象属性(Javascript是基于对象的语言);

      

    >>> d = Derived2()

    >>> d.__bases__

    Traceback (most recent call last):

    File "<stdin>", line 1, in <module>

    AttributeError: 'Derived2' object has no attribute '__bases__'

    >>> d.__class__

    <class '__main__.Derived2'>

    >>> d.__class__.__bases__

    (<class '__main__.Derived'>, <class '__main__.Base'>)

      

    对象的__class__属性指明了所属类型;

    >>> [].__class__

    <class 'list'>

    >>> ().__class__

    <class 'tuple'>

    >>> 1.__class__

    File "<stdin>", line 1

    1.__class__

    ^

    SyntaxError: invalid syntax

      

    >>> type(1)

    <class 'int'>

    在Python中1,是对象还是基本类型?

      

    __mro__

    __mro__给出了method resolution order,即解析方法调用的顺序

      

    >>> Derived.__mro__

    (<class '__main__.Derived'>, <class '__main__.Base'>, <class 'object'>)

    >>> Derived2.__mro__

    (<class '__main__.Derived2'>, <class '__main__.Derived'>, <class '__main__.Base'>, <class 'object'>)

      

    看上去和__bases__相像,仅仅是最后面多了个<class 'object'>

      

    super

    super函数能够用于调用父类的方法,而后者可能被子类覆盖;类似在java中的作用,但使用起来更复杂些。

    >>> class Base:

    ... pass

    ...

    >>> class Derived(Base):

    ... pass

    ...

    >>> class Derived2(Derived)

    File "<stdin>", line 1

    class Derived2(Derived)

    ^

    SyntaxError: invalid syntax

    >>> class Derived2(Derived):

    ... pass

    ...

    >>> d = Derived2()

    >>> super(Derived2, d)

    <super: <class 'Derived2'>, <Derived2 object>>

    >>> super(Derived, d)

    <super: <class 'Derived'>, <Derived2 object>>

    >>> super(Base, d)

    <super: <class 'Base'>, <Derived2 object>>

      

    參考https://docs.python.org/2/library/functions.html#super

    super(type[, object-or-type])

    Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.

      

    The __mro__ attribute of the type lists the method resolution search order used by both getattr() and super().

      

    >>> isinstance(super(Base, d), Base)

    False

    >>> isinstance(super(Derived, d), Base)

    False

    代理对象并非类层次中某个类的实例!

      

    结合多重继承来理解下__mro__和super

    class A:

    def __init__(self):

    print('enter __init__@A')

    super(A,self).__init__()

    print('exit __init__@A')

    class B(A):

    def __init__(self):

    print('enter __init__@B')

    super(B,self).__init__()

    print('exit __init__@B')

    class C(A):

    def __init__(self):

    print('enter __init__@C')

    super(C,self).__init__()

    print('exit __init__@C')

    class D(A):

    def __init__(self):

    print('enter __init__@D')

    super(D,self).__init__()

    print('exit __init__@D')

    class E(B,C):

    def __init__(self):

    print('enter __init__@E')

    super(E,self).__init__()

    print('exit __init__@E')

    class F(E,D):

    def __init__(self):

    print('enter __init__@F')

    super(F,self).__init__()

    print('exit __init__@F')

      

    if __name__ == '__main__':

    A()

    print(A.__mro__)        

    B()

    print(B.__mro__)        

    C()

    print(C.__mro__)        

    D()

    print(D.__mro__)        

    E()

    print(E.__mro__)        

    F()

    print(F.__mro__)

    执行结果

    enter __init__@A

    exit __init__@A

    (<class '__main__.A'>, <class 'object'>)

    enter __init__@B

    enter __init__@A

    exit __init__@A

    exit __init__@B

    (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

    enter __init__@C

    enter __init__@A

    exit __init__@A

    exit __init__@C

    (<class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

    enter __init__@D

    enter __init__@A

    exit __init__@A

    exit __init__@D

    (<class '__main__.D'>, <class '__main__.A'>, <class 'object'>)

    enter __init__@E

    enter __init__@B

    enter __init__@C

    enter __init__@A

    exit __init__@A

    exit __init__@C

    exit __init__@B

    exit __init__@E

    (<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

    enter __init__@F

    enter __init__@E

    enter __init__@B

    enter __init__@C

    enter __init__@D

    enter __init__@A

    exit __init__@A

    exit __init__@D

    exit __init__@C

    exit __init__@B

    exit __init__@E

    exit __init__@F

    (<class '__main__.F'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)

    观察到,super的运行路径和类的__mro__列举的类顺序吻合;而__mro__的顺序能够看作是深搜的结果

    A

    / |

    B C D

    / /

    E /

    /

    F

    class E(B, C)中,B和C不是基-派生类关系,E.__mro__中B在C之前,须要注意;

      

    多态

      

    >>> class Base:

    ... def sayHello(self):

    ... print("Base says hello")

    ...

    >>> class Derived(Base):

    ... pass

    ...

    >>> d = Derived()

    >>> d.sayHello()

    Base says hello

    Derived重写sayHello

    >>> class Derived(Base):

    ... def sayHello(self):

    ... print("Derived says hello");

    ...

    >>> d = Derived()

    >>> d.sayHello()

    Derived says hello

      

    与參数默认值结合(联想起了C++)

    >>> class Base:

    ... def sayHello(self, str="Base"):

    ... print("Base says: " + str)

    ...

    >>> class Derived(Base):

    ... def sayHello(self, str="Derived"):

    ... print("Dervied says: " + str)

    ...

    >>>

    >>> d = Derived()

    >>> d.sayHello()

    Dervied says: Derived

    >>> Base.sayHello(d)

    Base says: Base

    >>> super(Derived, d).sayHello()

    Base says: Base

      

    看一下,在基类构造函数中调用被覆盖方法的行为

    >>> class Base:

    ... def sayHello(self):

    ... str = self.getStr()

    ... print("Base says: " + str)

    ... def getStr(self):

    ... return "Base"

    ...

    >>> class Derived(Base):

    ... def getStr(self):

    ... return "Derived"

    ...

    >>>

    >>> d = Derived()

    >>> d.sayHello()

    Base says: Derived

    >>> def Base_init(self):

    ... self.sayHello()

    ...

    >>> Base.__init__ = Base_init

    >>> d = Derived()

    Base says: Derived

    可见,行为类似Java,调用了子类的覆盖方法;

      

  • 相关阅读:
    mysql编码和Java编码相应一览表
    Swift开发之 使用系统的TabbarController
    Shiro Quartz之Junit測试Session管理
    爱加密Android APk 原理解析
    【机器学习基础】自适应提升
    select默认选择的实现方法
    怎样找对还有一半--第一章 品行与择偶关系
    一步步教你怎样自己主动部署博客
    HTML5的新特性
    DataTables Table plug-in for jQuery
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4085304.html
Copyright © 2011-2022 走看看