欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python中的super().__init__()用法詳解

 更新時間:2025年06月13日 10:16:51   作者:kanhao100  
我們在學習Python類的時候,總會碰見書上的類中有__init__()這樣一個函數(shù),這篇文章主要介紹了Python中的super().__init__()用法的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

基本概念

class SingleConv(nn.Module):
    def __init__(self):
        super(SingleConv, self).__init__()
        self.conv = nn.Conv2d(3, 16, kernel_size=3, padding=1)
    
    def forward(self, x):
        return self.conv(x)

super(SingleConv, self).__init__() 這行代碼用于調(diào)用父類(基類)的初始化方法。具體來說,它讓 SingleConv 類調(diào)用其父類 nn.Module 的 __init__() 方法,確保父類被正確初始化。

這是面向對象編程中繼承機制的重要組成部分,特別是在構建 PyTorch 神經(jīng)網(wǎng)絡模型時尤為關鍵。

語法分解

讓我們逐部分解析這個表達式:

  • super() - 這是 Python 內(nèi)置函數(shù),用于返回一個代理對象,該對象將方法調(diào)用委托給父類或兄弟類。

  • super(SingleConv, self) - 這部分創(chuàng)建了一個代理對象,指向 SingleConv 類的父類(在這個例子中是 nn.Module)。第一個參數(shù)指定類本身,第二個參數(shù)通常是類的實例(即 self)。

  • super(SingleConv, self).__init__() - 通過代理對象調(diào)用父類的 __init__() 方法,確保父類的初始化代碼被執(zhí)行。

為什么這很重要?

一般繼承原則

在繼承關系中,子類需要確保父類被正確初始化,因為:

  • 父類可能設置了子類依賴的重要屬性和狀態(tài)
  • 父類可能執(zhí)行了必要的初始化邏輯
  • 如果不調(diào)用父類的初始化方法,繼承鏈就會斷開,子類將無法完全繼承父類的功能

在 PyTorch 中的特殊重要性

在 PyTorch 的 nn.Module 上下文中,調(diào)用 super().__init__() 尤為關鍵,因為:

  • 參數(shù)管理 - nn.Module 的初始化方法設置了追蹤和管理模型參數(shù)(如卷積層的權重和偏置)的機制

  • 模塊注冊 - 它建立了子模塊的注冊系統(tǒng),使 PyTorch 能夠識別模型的層次結構

  • 功能支持 - 它啟用了許多核心功能,包括:

    • 參數(shù)遷移(使用 .to(device) 將模型移動到 CPU/GPU)
    • 模型保存和加載(使用 torch.save() 和 torch.load()
    • 訓練和評估模式切換(.train() 和 .eval()
    • 自動求導支持

如果省略會發(fā)生什么?

如果您省略 super().__init__() 調(diào)用,可能會導致:

class SingleConvWithoutSuper(nn.Module):
    def __init__(self):
        # 沒有調(diào)用 super().__init__()
        self.conv = nn.Conv2d(3, 16, kernel_size=3, padding=1)
    
    def forward(self, x):
        return self.conv(x)

model = SingleConvWithoutSuper()
print(list(model.parameters()))  # 可能返回空列表,因為參數(shù)沒有被正確注冊

這樣的模型會出現(xiàn)多種問題:

  • 參數(shù)不會被正確注冊和跟蹤
  • 無法正常使用 .to(device) 遷移到 GPU
  • 保存和加載模型時可能丟失參數(shù)
  • 梯度可能無法正確傳播

Python 3 的簡化語法

在 Python 3 中,可以使用更簡潔的語法:

class SingleConv(nn.Module):
    def __init__(self):
        super().__init__()  # 簡化版,等效于 super(SingleConv, self).__init__()
        self.conv = nn.Conv2d(3, 16, kernel_size=3, padding=1)
    
    def forward(self, x):
        return self.conv(x)

這種寫法功能完全相同,但更簡潔易讀。Python 3 的 super() 不帶參數(shù)時會自動使用當前類和實例。

多重繼承中的作用

在涉及多重繼承的復雜情況下,super() 特別有用。它會按照方法解析順序(MRO)正確調(diào)用父類,避免同一個父類被初始化多次:

class A:
    def __init__(self):
        print("A init")

class B(A):
    def __init__(self):
        super().__init__()
        print("B init")

class C(A):
    def __init__(self):
        super().__init__()
        print("C init")

class D(B, C):
    def __init__(self):
        super().__init__()
        print("D init")

當創(chuàng)建 D 的實例時,super() 確保每個父類的 __init__ 只被調(diào)用一次,遵循 Python 的 MRO 規(guī)則。

執(zhí)行結果

當我們創(chuàng)建 D 類的實例(如 d = D())時,輸出結果為:

A init
C init
B init
D init

這個輸出順序可能看起來有些反直覺,特別是 C init 出現(xiàn)在 B init 之前,盡管在 D 的繼承聲明中 B 是第一個父類。讓我們深入分析這是為什么。

方法解析順序 (MRO)

Python 使用一種稱為方法解析順序(Method Resolution Order, MRO)的機制來確定多重繼承中方法查找的順序。MRO 決定了當調(diào)用 super() 時,Python 應該按照什么順序查找父類的方法。

我們可以通過以下方式查看一個類的 MRO:

print(D.__mro__)  # 或者 print(D.mro())

對于我們的例子,D 類的 MRO 是:

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

這意味著 Python 在 D 的實例上查找方法時,會按照 D -> B -> C -> A -> object 的順序搜索。

super() 的工作原理

理解 super() 的關鍵在于:super() 不是簡單地調(diào)用父類的方法,而是調(diào)用 MRO 中當前類之后的下一個類的方法

當在一個類中使用 super().__init__() 時,Python 會查找 MRO 中當前類之后的下一個類,并調(diào)用其 __init__ 方法。這是一個非常強大的機制,尤其是在處理復雜的繼承結構時。

詳細的執(zhí)行流程

讓我們逐步追蹤 D() 創(chuàng)建實例時的執(zhí)行流程:

  • 調(diào)用 D.__init__()

    • 執(zhí)行 super().__init__()
    • 根據(jù) MRO,D 之后的類是 B,所以調(diào)用 B.__init__()
  • 進入 B.__init__()

    • 執(zhí)行 super().__init__()
    • 根據(jù) MRO,B 之后的類是 C,所以調(diào)用 C.__init__()
  • 進入 C.__init__()

    • 執(zhí)行 super().__init__()
    • 根據(jù) MRO,C 之后的類是 A,所以調(diào)用 A.__init__()
  • 進入 A.__init__()

    • 打印 "A init"
    • A.__init__() 執(zhí)行完畢,返回到 C.__init__()
  • 回到 C.__init__()

    • 打印 "C init"
    • C.__init__() 執(zhí)行完畢,返回到 B.__init__()
  • 回到 B.__init__()

    • 打印 "B init"
    • B.__init__() 執(zhí)行完畢,返回到 D.__init__()
  • 回到 D.__init__()

    • 打印 "D init"
    • D.__init__() 執(zhí)行完畢

圖解說明

下面是繼承結構和執(zhí)行順序的圖解:

    A
   / \
  B   C
   \ /
    D

執(zhí)行順序(箭頭表示調(diào)用方向):

D.__init__() → B.__init__() → C.__init__() → A.__init__()
                                                 ↓
D.__init__() ← B.__init__() ← C.__init__() ← 返回并打印 "A init"
     ↓              ↓              ↓
     ↓              ↓         打印 "C init"
     ↓         打印 "B init"
打印 "D init"

與直接調(diào)用父類方法的對比

為了理解 super() 的價值,讓我們看看如果不使用 super() 而是直接調(diào)用父類的 __init__ 方法會發(fā)生什么:

class A:
    def __init__(self):
        print("A init")

class B(A):
    def __init__(self):
        A.__init__(self)  # 直接調(diào)用 A.__init__
        print("B init")

class C(A):
    def __init__(self):
        A.__init__(self)  # 直接調(diào)用 A.__init__
        print("C init")

class D(B, C):
    def __init__(self):
        B.__init__(self)  # 直接調(diào)用 B.__init__
        C.__init__(self)  # 直接調(diào)用 C.__init__
        print("D init")

使用這種方式,創(chuàng)建 D 的實例將輸出:

A init  # 從 B.__init__ 調(diào)用
B init
A init  # 從 C.__init__ 調(diào)用,A 被初始化了兩次!
C init
D init

可以看到,A.__init__() 被調(diào)用了兩次!這可能導致資源重復分配、狀態(tài)不一致或其他問題。

總結

super(SingleConv, self).__init__() 這行代碼是確保 PyTorch 神經(jīng)網(wǎng)絡模塊正確初始化的關鍵步驟。它調(diào)用父類 nn.Module 的初始化方法,設置必要的內(nèi)部狀態(tài),并啟用 PyTorch 的核心功能。

在 Python 3 中,推薦使用更簡潔的 super().__init__() 語法。無論使用哪種形式,確保在每個繼承自 nn.Module 的類的 __init__ 方法中調(diào)用它,這是構建正確功能的 PyTorch 模型的基礎。

簡單來說,這行代碼就像告訴您的類:“在我開始自己的初始化工作之前,請確保我從父類繼承的所有功能都已正確設置好。”

到此這篇關于Python中的super().__init__()用法詳解的文章就介紹到這了,更多相關Python中super().__init__()內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論