神经网络super(XXX, self).__init__()到底代表什么

在李沐:动手学深度学习第9章第7节:序列到序列学习(Seq2Seq)中,有以下代码:

#@save
class Seq2SeqEncoder(d2l.Encoder):
    """用于序列到序列学习的循环神经网络编码器"""
    def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,
                 dropout=0, **kwargs):
        super(Seq2SeqEncoder, self).__init__(**kwargs)
        # 嵌入层
        self.embedding = nn.Embedding(vocab_size, embed_size)
        self.rnn = nn.GRU(embed_size, num_hiddens, num_layers,
                          dropout=dropout)

    def forward(self, X, *args):
        # 输出'X'的形状:(batch_size,num_steps,embed_size)
        X = self.embedding(X)
        # 在循环神经网络模型中,第一个轴对应于时间步
        X = X.permute(1, 0, 2)
        # 如果未提及状态,则默认为0
        output, state = self.rnn(X)
        # output的形状:(num_steps,batch_size,num_hiddens)
        # state的形状:(num_layers,batch_size,num_hiddens)
        return output, state

在Seq2SeqEncoder类中出现了super(Seq2SeqEncoder, self).__init__(**kwargs),有点疑惑的是下面的这三行代码是干什么用的,要看懂这三行代码需要了解三个东西:

  • self参数
  • __ init__ ()方法
  • super(Net, self).init()

接下来就为大家逐一讲解一下。

一、self参数

self指的是实例Instance本身,在Python类中规定,函数的第一个参数是实例对象本身,并且约定俗成,把其名字写为self,也就是说,类中的方法的第一个参数一定要是self,而且不能省略。
我觉得关于self有三点是很重要的:

  • self指的是实例本身,而不是类
  • self可以用this替代,但是不要这么去写
  • 类的方法中的self不可以省略

(1)self指的是实例本身,而不是类:

class Person():
    def eat(self):
        print(self)

Bob=Person() # 创建Person类的实例Bob
Bob.eat() # 调用eat
print(Person)

输出:

<__main__.Person object at 0x000002C383FBDA88> # Person类的实例Bob
<class '__main__.Person'> # Person是一个类

(2)self可以用this替代,但是一般不要这么去写:

class Person():
    def eat(this):
        print(this)

Bob=Person()
Bob.eat()
print(Person)

输出:

<__main__.Person object at 0x00000240E4C83908>
<class '__main__.Person'>

(3)类方法中的self不可以省略,Pycharm里面的提示:

 二、__ init__ ()方法

在python中创建类后,通常会创建一个__ init__ ()方法,这个方法会在创建类的实例的时候自动执行。 __ init__ ()方法必须包含一个self参数,而且要是第一个参数。

比如下面例子中的代码,在实例化Bob这个对象的时候, __ init__ ()方法就已经自动执行了,但是如果不是 __ init__ ()方法,比如说eat()方法,那肯定就只有调用才执行。

class Person():
    def __init__(self):
        print("是一个人")
    def eat(self):
        print("要吃饭" )
Bob=Person()

输出则自动调用init下面的print函数:

是一个人

接下来我们在__init__方法里面加入其他参数,比如传入name:

class Person():
    def __init__(self,name):
        print("是一个人")
        self.name=name
    def eat(self):
        print("%s要吃饭" %self.name)

Bob=Person('Bob')
Bob.eat()

输出:

是一个人
Bob要吃饭

注意:__init__方法里面给定参数name后,在创建类的实例的时候必须指定name,否则就会报错。

Bob=Person()
Bob.eat()

由于__init__方法可以自动调用,这样我们其实就比较清晰的知道什么东西需要在__ init__ ()方法中定义了,就是希望有一些操作是在创建实例的时候就有的时候。比如说下面的这个代码,其实就应该把money这个量定义在 __ init__ ()方法中,这样就不需要在执行eat()方法后再执行qian()方法。或者说我们写神经网络的代码的时候,一些网络结构的设置,也最好放在\ __ init__ ()方法中。

class Person():
    def __init__(self,name):
        print("是一个人")
        self.name=name
    def eat(self,money):
        print("%s要吃饭" %self.name)
        self.money=money
    def qian(self):
        print("花了%s元" %self.money)

Bob=Person('Bob')
Bob.eat(12)
Bob.qian()

三、super(Net, self).__init__()

Python中的super(Net, self).__init__()是指首先找到Net的父类(比如是类NNet),然后把类Net的对象self转换为类NNet的对象,然后“被转换”的类NNet对象调用自己的init函数,其实简单理解就是子类把父类的__init__()放到自己的__init__()当中,这样子类就有了父类的__init__()的那些东西。

回过头来看看我们的我们最上面的代码,Seq2SeqEncoder类继承d2l.Encoder,super(Net, self).__init__()就是对继承自父类d2l.Encoder的属性进行初始化。而且是用d2l.Encoder的初始化方法来初始化继承的属性。也就是说,子类继承了父类的所有属性和方法,父类属性自然会用父类方法来进行初始化。

举个例子帮助大家理解:

class Person:
    def __init__(self,name,gender):
        self.name = name
        self.gender = gender
    def printinfo(self):
        print(self.name,self.gender)

class Stu(Person):
    def __init__(self,name,gender,school):
        super(Stu, self).__init__(name,gender) # 使用父类的初始化方法来初始化子类
        self.school = school
    def printinfo(self): # 对父类的printinfo方法进行重写
        print(self.name,self.gender,self.school)

if __name__ == '__main__':
    stu = Stu('djk','man','nwnu')
    stu.printinfo()

当然,如果初始化的逻辑与父类的不同,不使用父类的方法,自己重新初始化也是可以的。比如:

class Person(object):
    def __init__(self,name,gender,age):
        self.name = name
        self.gender = gender
        self.age = age
 
class Student(Person):
    def __init__(self,name,gender,age,school,score):
        #super(Student,self).__init__(name,gender,age)
        self.name = name.upper()  
        self.gender = gender.upper()
        self.school = school
        self.score = score
 
s = Student('Alice','female',18,'Middle school',87)
print s.school
print s.name
  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值