Python类(class)参数self的理解

问题

在python类中,经常可以看见self参数,比如:

复制代码
class Net(nn.Module):
    def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2,
                 is_training=True):
        super().__init__()
        self.num_inputs = num_inputs
        self.training = is_training
        self.lin1 = nn.Linear(num_inputs, num_hiddens1)
        self.lin2 = nn.Linear(num_hiddens1, num_hiddens2)
        self.lin3 = nn.Linear(num_hiddens2, num_outputs)
        self.relu = nn.ReLU()

那么这个参数该如何理解呢?

self 是 Python 类(class)中最核心、最关键的概念之一。理解 self 对于掌握面向对象编程至关重要。


一、self 是什么?

self 是一个约定俗成的名称,它代表类的(实例)

  • 每当你创建一个类的实例(对象),Python 会自动把这个实例作为第一个参数传递给类中的方法。
  • self 就是用来接收这个"实例本身"的参数。

二、举个例子来理解

复制代码
class Person:
    def __init__(self, name):
        self.name = name  # 把传入的 name 保存到这个实例中

    def greet(self):
        print(f"Hello, I am {self.name}")

# 创建一个实例
p = Person("Alice")
p.greet()  # 输出:Hello, I am Alice

我们来一步步分析:

  1. p = Person("Alice")

    • 创建了一个 Person 类的实例,叫 p
    • Python 自动调用 __init__ 方法,并把 p 这个实例作为第一个参数传进去。
    • 所以在 __init__ 中,self 就是 p
    • self.name = name 相当于 p.name = "Alice"
  2. p.greet()

    • 调用 greet 方法。
    • Python 自动把 p 作为第一个参数传给 greet 方法。
    • 所以在 greet 中,self 也是 p
    • self.name 就是 p.name,也就是 "Alice"

三、为什么需要 self

因为一个类可以创建多个实例,每个实例有自己的数据。self 让每个方法都知道"我现在操作的是哪一个实例"。

复制代码
p1 = Person("Alice")
p2 = Person("Bob")

p1.greet()  # Hello, I am Alice
p2.greet()  # Hello, I am Bob

虽然 p1p2 都调用同一个 greet 方法,但 self 不同,所以访问的数据也不同。


四、self 在哪里出现?

  1. 定义方法时 :必须把 self 作为第一个参数。

    复制代码
    def greet(self):
        ...
  2. 访问实例变量或调用其他方法时 :用 self.xxx

    复制代码
    self.name = "Alice"
    self.greet()
  3. __init__ 中初始化属性

    复制代码
    def __init__(self, name):
        self.name = name
        self.age = 0

五、重要说明

  • self 只是一个名字,你 technically 可以叫它 thismyself 或其他名字,但 强烈建议始终使用 self,这是 Python 社区的统一约定。

  • self 参数在调用方法时不需要手动传 ,Python 会自动传。

    复制代码
    p.greet()  # 正确,不需要写 p.greet(p)

六、什么是需要self.param = param

回到神经网络代码

python 复制代码
dropout1, dropout2 = 0.2, 0.5

class Net(nn.Module):
    def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2,
                 is_training = True):
        super(Net, self).__init__()
        self.num_inputs = num_inputs
        self.training = is_training
        self.lin1 = nn.Linear(num_inputs, num_hiddens1)
        self.lin2 = nn.Linear(num_hiddens1, num_hiddens2)
        self.lin3 = nn.Linear(num_hiddens2, num_outputs)
        self.relu = nn.ReLU()

    def forward(self, X):
        H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))
        # 只有在训练模型时才使用dropout
        if self.training == True:
            # 在第一个全连接层之后添加一个dropout层
            H1 = dropout_layer(H1, dropout1)
        H2 = self.relu(self.lin2(H1))
        if self.training == True:
            # 在第二个全连接层之后添加一个dropout层
            H2 = dropout_layer(H2, dropout2)
        out = self.lin3(H2)
        return out


net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)
  • self.lin1 表示:这个网络实例的第一个线性层。
  • self.relu 表示:这个网络实例的激活函数。
  • 每个 Net 实例都有自己的一套 lin1, lin2 等层,self 帮助区分和管理它们。

一个问题,对于实例中的参数,为什么这里定义了

python 复制代码
self.num_inputs = num_inputs
self.training = is_training

但却没有定义

python 复制代码
self.num_outputs = num_inputs
self.num_hiddens1 = num_hiddens1

即为什么有些参数被保存为实例变量,而有些没有?

答案核心:是否需要在类的其他方法中使用这些参数

在 Python 类中,是否将某个变量保存为 self.xxx,取决于你是否希望在类的其他方法中访问它。

可以看到,在后续的def forward()中,调用了self.num_inputs、self.training,而没有调用到num_outputsnum_hiddens1


总结

概念 说明
self 代表当前类的实例(对象)
作用 让方法可以访问和修改实例的数据
出现位置 方法定义的第一个参数,访问属性/方法时用 self.xxx
是否手动传 否,Python 自动传
为什么重要 实现"一个类,多个实例,各自独立"
什么时候需要self.param=param 是否在后续的函数或方法中需要调用该变量
相关推荐
张人玉39 分钟前
c#Lambda 表达式与事件核心知识点整理
开发语言·python·c#
魔尔助理顾问8 小时前
系统整理Python的循环语句和常用方法
开发语言·后端·python
颜颜yan_10 小时前
Python面向对象编程详解:从零开始掌握类的声明与使用
开发语言·redis·python
我的ID配享太庙呀11 小时前
Django 科普介绍:从入门到了解其核心魅力
数据库·后端·python·mysql·django·sqlite
@蓝莓果粒茶12 小时前
LeetCode第350题_两个数组的交集II
c++·python·学习·算法·leetcode·职场和发展·c#
FinAnalyzer12 小时前
如何在 InsCodeAI 上搭建并使用 Jupyter Notebook 环境?
ide·python·jupyter
java1234_小锋12 小时前
【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博文章数据可视化分析-文章分类下拉框实现
python·自然语言处理·flask
檀越剑指大厂12 小时前
【Python系列】Flask 应用中的主动垃圾回收
开发语言·python·flask
檀越剑指大厂12 小时前
【Python系列】使用 memory_profiler 诊断 Flask 应用内存问题
开发语言·python·flask