python3 super().__init__()


父類不會自動調用__init__方法

class A:
    def __init__(self):
        A = 'A'
        self.a = 'a'
        print('init A')
        
class B(A):
    def __init__(self):
        self.b = 'b'
        print('init B')

b = B()
print(b.A)
print(b.a)
init B
A
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-62-6b0a00f52204> in <module>
      1 b = B()
      2 print(b.A)
----> 3 print(b.a)

AttributeError: 'B' object has no attribute 'a'

子類繼承父類,子類實例化只會調用自己的構造方法,父類的構造方法不會調用,或者說子類重寫了父類的構造方法,所以父類在構造方法中定義的默認屬性也無法繼承。
實例變量不能繼承不是Python繼承有問題,上面在class A中定義了一個類變量A就被成功繼承下來了,python類中的所有最外層類變量,類方法,靜態方法,實例方法該繼承都會繼承,不過實例變量是定義在__init__構造方法中的,雖然__init__會在實例化時自動執行(不管是父類還是子類),但子類重寫了父類方法,所以父類構造沒有執行,只是執行了子類構造。不然看下面一個例子:

class E(A):
    pass

e = E()
print(e.a)
init A
a

如果子類沒有重寫父類方法那么父類構造還是自動執行了。所以總的來說父類構造沒有執行的原因是子類重寫了父類的__init__方法

使用super().init()手動執行父類的構造方法

如果要手動執行, 首先絕不能這樣:

class B(A):
    def __init__(self):
        self.__init__()
        self.b = 'b'
        print('init B')

b = B()
print(b.A)
print(b.a)
---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
<ipython-input-68-6b0a00f52204> in <module>
----> 1 b = B()
      2 print(b.A)
      3 print(b.a)

<ipython-input-67-7b74bc3d523e> in __init__(self)
      7 class B(A):
      8     def __init__(self):
----> 9         self.__init__()
     10         self.b = 'b'
     11         print('init B')

... last 1 frames repeated, from the frame below ...

<ipython-input-67-7b74bc3d523e> in __init__(self)
      7 class B(A):
      8     def __init__(self):
----> 9         self.__init__()
     10         self.b = 'b'
     11         print('init B')

RecursionError: maximum recursion depth exceeded

這樣做的后果是會無限遞歸調用子類自己的__init__
不過可以手動指定父類類名進行調用,比如下面這樣:

class B(A):
    def __init__(self):
        A.__init__(self)
        self.b = 'b'
        print('init B')

b = B()
print(b.A)
print(b.a)
init A
init B
A
a

這樣做是可以成功的,缺點就是太累了,在多繼承環境下我們需要指定每一個父類進行調用,比如下面這樣

class B(A):
    def __init__(self):
        A.__init__(self)
        self.b = 'b'
        print('init B')
    
class C(A):
    def __init__(self):
        self.c = 'c'
        print('init C')
        
class D(B,C):
    def __init__(self):
        B.__init__(self)
        C.__init__(self)
        self.d = 'd'
        print('init D')

d = D()
print(d.b)
print(d.c)
init A
init B
init C
init D
b
c

顯然B需要調A,D需要調用B和C,顯然不符合python的優雅風格
super().__init__的好處就是統一進行所有父類構造方法的調用,調用的先后根據類型的mro順序決定,將自動調用所有父類的構造方法
我們這里只關注直系父類,因為對於祖父級別的類構造方法是否調用取決於父類中是否重寫了祖父的構造方法,只要在繼承的父類中有一個父類重寫了祖父的構造方法,那么祖父的構造方法也不會被調用。
我們可以根據<class>.mro()查看類型的MRO表

print(D.mro())

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

super().init()是python3中簡化后的方法,功能和super(self.class, self).init()一樣


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM