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

 更新时间:2025年06月13日 10:16:51   作者:kanhao100  
我们在学习Python类的时候,总会碰见书上的类中有__init__()这样一个函数,这篇文章主要介绍了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__() 这行代码用于调用父类(基类)的初始化方法。具体来说,它让 SingleConv 类调用其父类 nn.Module 的 __init__() 方法,确保父类被正确初始化。

这是面向对象编程中继承机制的重要组成部分,特别是在构建 PyTorch 神经网络模型时尤为关键。

语法分解

让我们逐部分解析这个表达式:

  • super() - 这是 Python 内置函数,用于返回一个代理对象,该对象将方法调用委托给父类或兄弟类。

  • super(SingleConv, self) - 这部分创建了一个代理对象,指向 SingleConv 类的父类(在这个例子中是 nn.Module)。第一个参数指定类本身,第二个参数通常是类的实例(即 self)。

  • super(SingleConv, self).__init__() - 通过代理对象调用父类的 __init__() 方法,确保父类的初始化代码被执行。

为什么这很重要?

一般继承原则

在继承关系中,子类需要确保父类被正确初始化,因为:

  • 父类可能设置了子类依赖的重要属性和状态
  • 父类可能执行了必要的初始化逻辑
  • 如果不调用父类的初始化方法,继承链就会断开,子类将无法完全继承父类的功能

在 PyTorch 中的特殊重要性

在 PyTorch 的 nn.Module 上下文中,调用 super().__init__() 尤为关键,因为:

  • 参数管理 - nn.Module 的初始化方法设置了追踪和管理模型参数(如卷积层的权重和偏置)的机制

  • 模块注册 - 它建立了子模块的注册系统,使 PyTorch 能够识别模型的层次结构

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

    • 参数迁移(使用 .to(device) 将模型移动到 CPU/GPU)
    • 模型保存和加载(使用 torch.save() 和 torch.load()
    • 训练和评估模式切换(.train() 和 .eval()
    • 自动求导支持

如果省略会发生什么?

如果您省略 super().__init__() 调用,可能会导致:

class SingleConvWithoutSuper(nn.Module):
    def __init__(self):
        # 没有调用 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()))  # 可能返回空列表,因为参数没有被正确注册

这样的模型会出现多种问题:

  • 参数不会被正确注册和跟踪
  • 无法正常使用 .to(device) 迁移到 GPU
  • 保存和加载模型时可能丢失参数
  • 梯度可能无法正确传播

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() 不带参数时会自动使用当前类和实例。

多重继承中的作用

在涉及多重继承的复杂情况下,super() 特别有用。它会按照方法解析顺序(MRO)正确调用父类,避免同一个父类被初始化多次:

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")

当创建 D 的实例时,super() 确保每个父类的 __init__ 只被调用一次,遵循 Python 的 MRO 规则。

执行结果

当我们创建 D 类的实例(如 d = D())时,输出结果为:

A init
C init
B init
D init

这个输出顺序可能看起来有些反直觉,特别是 C init 出现在 B init 之前,尽管在 D 的继承声明中 B 是第一个父类。让我们深入分析这是为什么。

方法解析顺序 (MRO)

Python 使用一种称为方法解析顺序(Method Resolution Order, MRO)的机制来确定多重继承中方法查找的顺序。MRO 决定了当调用 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() 不是简单地调用父类的方法,而是调用 MRO 中当前类之后的下一个类的方法

当在一个类中使用 super().__init__() 时,Python 会查找 MRO 中当前类之后的下一个类,并调用其 __init__ 方法。这是一个非常强大的机制,尤其是在处理复杂的继承结构时。

详细的执行流程

让我们逐步追踪 D() 创建实例时的执行流程:

  • 调用 D.__init__()

    • 执行 super().__init__()
    • 根据 MRO,D 之后的类是 B,所以调用 B.__init__()
  • 进入 B.__init__()

    • 执行 super().__init__()
    • 根据 MRO,B 之后的类是 C,所以调用 C.__init__()
  • 进入 C.__init__()

    • 执行 super().__init__()
    • 根据 MRO,C 之后的类是 A,所以调用 A.__init__()
  • 进入 A.__init__()

    • 打印 "A init"
    • A.__init__() 执行完毕,返回到 C.__init__()
  • 回到 C.__init__()

    • 打印 "C init"
    • C.__init__() 执行完毕,返回到 B.__init__()
  • 回到 B.__init__()

    • 打印 "B init"
    • B.__init__() 执行完毕,返回到 D.__init__()
  • 回到 D.__init__()

    • 打印 "D init"
    • D.__init__() 执行完毕

图解说明

下面是继承结构和执行顺序的图解:

    A
   / \
  B   C
   \ /
    D

执行顺序(箭头表示调用方向):

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

与直接调用父类方法的对比

为了理解 super() 的价值,让我们看看如果不使用 super() 而是直接调用父类的 __init__ 方法会发生什么:

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

class B(A):
    def __init__(self):
        A.__init__(self)  # 直接调用 A.__init__
        print("B init")

class C(A):
    def __init__(self):
        A.__init__(self)  # 直接调用 A.__init__
        print("C init")

class D(B, C):
    def __init__(self):
        B.__init__(self)  # 直接调用 B.__init__
        C.__init__(self)  # 直接调用 C.__init__
        print("D init")

使用这种方式,创建 D 的实例将输出:

A init  # 从 B.__init__ 调用
B init
A init  # 从 C.__init__ 调用,A 被初始化了两次!
C init
D init

可以看到,A.__init__() 被调用了两次!这可能导致资源重复分配、状态不一致或其他问题。

总结

super(SingleConv, self).__init__() 这行代码是确保 PyTorch 神经网络模块正确初始化的关键步骤。它调用父类 nn.Module 的初始化方法,设置必要的内部状态,并启用 PyTorch 的核心功能。

在 Python 3 中,推荐使用更简洁的 super().__init__() 语法。无论使用哪种形式,确保在每个继承自 nn.Module 的类的 __init__ 方法中调用它,这是构建正确功能的 PyTorch 模型的基础。

简单来说,这行代码就像告诉您的类:“在我开始自己的初始化工作之前,请确保我从父类继承的所有功能都已正确设置好。”

到此这篇关于Python中的super().__init__()用法详解的文章就介绍到这了,更多相关Python中super().__init__()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 基于PyQt5制作一个截图翻译工具

    基于PyQt5制作一个截图翻译工具

    这篇文章主要为大家介绍了如何利用PyQt5制作一个简单的截图翻译工具,具有截图功能、翻译功能和文字识别OCR,需要的可以参考一下
    2022-05-05
  • python3之读取redis数据带有‘b’的问题

    python3之读取redis数据带有‘b’的问题

    这篇文章主要介绍了python3之读取redis数据带有‘b’的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • python中如何让输出不换行

    python中如何让输出不换行

    这篇文章主要介绍了python中如何让输出不换行问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • Python中将变量按行写入txt文本中的方法

    Python中将变量按行写入txt文本中的方法

    下面小编就为大家分享一篇Python中将变量按行写入txt文本中的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-04-04
  • python基于twisted框架编写简单聊天室

    python基于twisted框架编写简单聊天室

    这篇文章主要为大家详细介绍了python基于twisted框架编写简单聊天室,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • python密码学列置换密码学习

    python密码学列置换密码学习

    这篇文章主要为大家介绍了python密码学列置换密码学习的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • python中无法导入本地安装好的第三方库问题

    python中无法导入本地安装好的第三方库问题

    这篇文章主要介绍了python中无法导入本地安装好的第三方库问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • python通过tcp发送xml报文的方法

    python通过tcp发送xml报文的方法

    今天小编就为大家分享一篇python通过tcp发送xml报文的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • Jmeter中JSR223设置变量方式

    Jmeter中JSR223设置变量方式

    本文主要介绍了JMeter的几种常用变量设置方式,特别对JSR223设置变量进行了详细解释,JSR223是Java规范请求,可以向Java平台增添新的API和服务,JSR223Sampler可以使用JSR223脚本代码执行创建/更新变量所需的示例或一些计算
    2024-10-10
  • pandas获取groupby分组里最大值所在的行方法

    pandas获取groupby分组里最大值所在的行方法

    下面小编就为大家分享一篇pandas获取groupby分组里最大值所在的行方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-04-04

最新评论