【问题标题】:Using self in init part of a class in Python在 Python 类的 init 部分中使用 self
【发布时间】:2021-05-06 19:23:30
【问题描述】:

以下两个与Python中初始化类相关的代码有什么区别吗?

class summation: 
    def __init__(self, f, s): 
        self.first = f 
        self.second = s 
        self.summ = self.first + self.second
    .
    .
    .

class summation: 
    def __init__(self, f, s): 
        self.first = f 
        self.second = s 
        self.summ = f + s
    .
    .
    .

如果有任何区别,那是什么,哪个代码更可取?

编辑:我打算用 Python(和 Pytorch)编写一个人工神经网络。其实上面的两个代码只是一些例子。在实际案例中,我在各种资源中看到,当一个类的初始化中存在self.input = input时,在其他部分它被用作self.input,而不是input

我的问题:这两种方法有什么区别?为什么在我的情况下使用self.input 更可取?

示例:(来自https://docs.dgl.ai/en/latest/tutorials/models/1_gnn/4_rgcn.html#sphx-glr-tutorials-models-1-gnn-4-rgcn-py

import torch
import torch.nn as nn
import torch.nn.functional as F
from dgl import DGLGraph
import dgl.function as fn
from functools import partial

class RGCNLayer(nn.Module):
    def __init__(self, in_feat, out_feat, num_rels, num_bases=-1, bias=None,
                 activation=None, is_input_layer=False):
        super(RGCNLayer, self).__init__()
        self.in_feat = in_feat
        self.out_feat = out_feat
        self.num_rels = num_rels
        self.num_bases = num_bases
        self.bias = bias
        self.activation = activation
        self.is_input_layer = is_input_layer

        # sanity check
        if self.num_bases <= 0 or self.num_bases > self.num_rels:
            self.num_bases = self.num_rels

        # weight bases in equation (3)
        self.weight = nn.Parameter(torch.Tensor(self.num_bases, self.in_feat,
                                                self.out_feat))
        if self.num_bases < self.num_rels:
            # linear combination coefficients in equation (3)
            self.w_comp = nn.Parameter(torch.Tensor(self.num_rels, self.num_bases))

        # add bias
        if self.bias:
            self.bias = nn.Parameter(torch.Tensor(out_feat))

        # init trainable parameters
        nn.init.xavier_uniform_(self.weight,
                                gain=nn.init.calculate_gain('relu'))
        if self.num_bases < self.num_rels:
            nn.init.xavier_uniform_(self.w_comp,
                                    gain=nn.init.calculate_gain('relu'))
        if self.bias:
            nn.init.xavier_uniform_(self.bias,
                                    gain=nn.init.calculate_gain('relu'))

    def forward(self, g):
        if self.num_bases < self.num_rels:
            # generate all weights from bases (equation (3))
            weight = self.weight.view(self.in_feat, self.num_bases, self.out_feat)
            weight = torch.matmul(self.w_comp, weight).view(self.num_rels,
                                                        self.in_feat, self.out_feat)
        else:
            weight = self.weight

        if self.is_input_layer:
            def message_func(edges):
                # for input layer, matrix multiply can be converted to be
                # an embedding lookup using source node id
                embed = weight.view(-1, self.out_feat)
                index = edges.data['rel_type'] * self.in_feat + edges.src['id']
                return {'msg': embed[index] * edges.data['norm']}
        else:
            def message_func(edges):
                w = weight[edges.data['rel_type']]
                msg = torch.bmm(edges.src['h'].unsqueeze(1), w).squeeze()
                msg = msg * edges.data['norm']
                return {'msg': msg}

        def apply_func(nodes):
            h = nodes.data['h']
            if self.bias:
                h = h + self.bias
            if self.activation:
                h = self.activation(h)
            return {'h': h}

        g.update_all(message_func, fn.sum(msg='msg', out='h'), apply_func)

【问题讨论】:

  • 我会挑战——如果 self.firstself.second 被更改,self.summ 就会过时。相反,它应该是在访问时计算的属性。鉴于self.firstself.second 可能 是属性,这两个版本实际上可能具有不同的行为,因此在您的上下文中哪种行为有意义并不是偏好问题。
  • @jonrsharpe 感谢您的评论。请给我一个例子,上面两个代码有不同的行为吗?
  • 如果summation.firstsummation.second描述符(例如property),它可能会有所不同,因为那时self.first 和@ 987654338@ 会调用描述符的__get__ 方法,可以任意操作。
  • @ZahraTaheri 看看我编辑的答案。我希望它现在为您澄清一切:)

标签: python-3.x class neural-network pytorch self


【解决方案1】:

。在您的情况下,这两种方法之间没有区别,具有这种信息水平。但他们可以吗? 是的。他们可以。如果他们的 settersgetters 有一些修改。稍后在我的回答中,我会告诉你怎么做。

首先,我更喜欢使用这个:

class summation: 
    def __init__(self, f, s): 
        self.first = f 
        self.second = s 
    @property
    def summ(self):
        return self.first+self.second

上述实现按需计算总和。因此,当您更改self.firstself.second 时,summ 将自动计算。您可以像以前一样访问总和。

s = summation(1,9)
print(s.summ)
# 10
s.first = 2
s.second = 3
print(s.summ)
# 5

那么,它们有什么不同呢?

让我们按如下方式实现它们。在 setters 中,我将输入加倍,以向您展示 setters 如何影响结果。这只是一个虚构的例子,并不是你写的。

class summation1: 
    def __init__(self, f, s): 
        self.first = f 
        self.second = s 
        self.summ = self.first + self.second

    @property
    def first(self):
      return self.__first

    @first.setter
    def first(self,f):
      self.__first = f*2

    @property
    def second(self):
      return self.__second

    @second.setter
    def second(self,s):
      self.__second = s*2


class summation2: 
    def __init__(self, f, s): 
        self.first = f 
        self.second = s 
        self.summ = f + s

    @property
    def first(self):
      return self.__first

    @first.setter
    def first(self,f):
      self.__first = f*2

    @property
    def second(self):
      return self.__second

    @second.setter
    def second(self,s):
      self.__second = s*2

现在让我们看看输出:

a = 3
b = 2
s1 = summation1(a,b)
s2 = summation2(a,b)

print(s1.summ)
# 10
print(s2.summ)
# 5

所以,如果您不确定在这两者之间选择什么,也许第一种方法就是您所需要的。

【讨论】:

  • 可以有所不同 - 如果self.firstself.second 也是属性怎么办?
  • @ZahraTaheri 如果您没有更改 self.firstself.second 中的任何内容,结果将是相同的。顺便说一句,当您不确定在这两者之间选择什么时,第一种方法 (self.first+self.second) 总是更安全。但我强烈建议您使用第三个(我的方法)
  • @MahradHanaforoosh 非常感谢您的回答。我在我的问题中添加了一些部分。
  • @MahradHanaforoosh 非常感谢您的有用回答。
  • @ZahraTaheri 欢迎您。我很高兴能帮上忙。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-06
  • 2011-03-04
  • 1970-01-01
  • 2011-05-14
  • 2020-09-20
  • 1970-01-01
相关资源
最近更新 更多