__init__()与__getitem__()及__len__()

__init__()用于类的初始化,几乎在任何框架定义类时都避免不了使用它,因为它负责创建类的实例属性并进行赋值等重要操作,尽管在新建对象时并不需要“显式”调用这个函数。

(不使用pytorch框架可以忽略:此外,在pytorch中,如果需要自定义Dataset,就需要实现__getitem__()和__len__()方法。自己当初比较疑惑为什么这两个方法不需要“显式调用”?另外,pytorch的nn.Sequential类也包含__getitem__()和__len__(),这两个方法究竟是如何起作用的?)

java中也包含setter与getter的使用方式,可以由于二者的设计理念不同,并不能等价的看待。

这篇笔记主要记录以下3点:

(1)魔方方法如何起作用

(2)自定义类,实现三个魔法方法并分析其作用

(3)完整代码

1、魔法方法如何起作用

python包含__call__、__init__、__bool__等等一系列魔法方法,比如__call__方法就在pytorch的Module类中经常被用到。网上讲魔法方法的文章很多,但是很少有讲到背后的原理的。自己从书中找到这样一句话“python解释器遇到特殊句法时,会去调用特殊方法,这些特殊方法以双下划线开头”。下面以__str__()方法作为一个例子引出下文:

class Fun:
    def __str__(self):
        return "it was called"
fun = Fun()
print(fun)

如果print()函数的参数是这个对象,那么会输出什么呢?

没错,就是"it was called",python解释器自动的调用了__str__()方法,这个方法的作用主要就是提供对象的文字描述信息。

2、自定义类,实现三个魔法方法并分析其作用

首先给出类的结构,定义一个Fun类,并实现上述的三个魔法方法如下:

class Fun:
    def __init__(self, x_list):
        #内容
    
    def __getitem__(self, idx):
        #内容
    
    def __len__(self):
        #内容

2.1 __init__()函数实现

__init__()方法负责初始化,根据自己的经验,必须要对初始化函数的参数进行类型检查,避免不必要的麻烦。slef表示这个方法是属于类实例的,而不是类的。(个人认为,python不像是java或者C++那样,它崇尚“万物皆引用”,如果不小心就会搞错对象类型),初始化函数如下:

函数中的self.data是非常重要的实例属性,后面的两个方法的意义实际上就是来获取这个实例属性的信息。

那么__init__函数是什么时候被调用的呢?其实它是在对象创建时被解释器自动调用的,现在创建一个实例试一试:

fun = Fun(x_list=[1, 2, 3, 4, 5])

终端会输出下面的字符串,说明__init__()函数被调用了:

intialize success

2.2 __getitem__()函数实现

对于value[0]这个使用方框索引,来获取序列中的指定位置的值的方法,相信大家一定很熟悉。但是如果自己定义一个类,能否使用索引的方式获取这个类实例的属性值?答案就是使用__getitem__()方法(这个方法的作用不止于此,以后笔记中关于迭代器和for语法中还要用到它)。

 def __getitem__(self, idx):
        print("__getitem__ is called")
        return self.data[idx]

__getitem__()方法接收一个idx参数,这个参数就是fun[2]中的2,也就是自己给的索引值。当fun[2]这个语句出现时,就会触发__getitem__(self,idx),这个方法就会返回self.data[2]。一个很自然的问题就是,self.data[2]这里为什么使用了[2]这种索引方式?这里应该由于self.data是list类型,[2]触发的是list的__getitem__方法。测试一下:

print(fun[2])

终端会输出下面两条,说明__getitem__被调用了:

__getitem__ is called
3

2.3 __len__()函数实现

python包含一个内置方法len(),使用它可以测量list、tuple等序列对象的长度,如下:

name = ["Li Hua", "Daming", "Honghong"]
print(len(name))

终端将会输出:3

那么如果自定义一个类,是不是也能使用len()函数测量某个实例属性的长度呢?只要实现__len__()就能实现这个功能,如下:

def __len__(self):
        print("__len__ is called")
        return len(self.data)

这时就能使用len()函数测量self.data的长度了,试一下:

print(len(fun))

终端输出下面两条,说明__len__()被自动调用了:

__len__ is called
5

3、完整代码

class Fun:
    def __init__(self, x_list):
        """ initialize the class instance
        Args:
            x_list: data with list type
        Returns:
            None
        """
        if not isinstance(x_list, list):
            raise ValueError("input x_list is not a list type")
        self.data = x_list
        print("intialize success")
    
    def __getitem__(self, idx):
        print("__getitem__ is called")
        return self.data[idx]
    
    def __len__(self):
        print("__len__ is called")
        return len(self.data)
    
fun = Fun(x_list=[1, 2, 3, 4, 5])
print(fun[2])
print(len(fun))

控制台输出:

intialize success
__getitem__ is called
3
__len__ is called
5

 

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值