如何在python中实现一个自定义的列表或字典

1,260 阅读3分钟

前情提要

在很多的python库之中,我们可以看到有的时候,库作者会使用一些很特殊的“列表”或者“字典”。虽然他们看起来很像是一个列表或者字典,但是使用的方法却又不一样,这是因为那不是真的python中原本的列表和字典,而是作者自己创建的。那么,我们如何可以创建我们自己的列表和字典呢?

魔法方法

前后都使用两个下划线的方法,一般被称之为魔法方法,比如我们常见的__init__,就是一种魔法方法。一般来说,我们自行定义变量名的时候,不要定义很像是魔法方法的变量名。魔法方法被定义后,可以在适当的时候自动被调用,一般不需要手动对其进行调用。

在python中,实现一个序列,我们需要以下四种魔法方法

__len__(self):这个方法应该返回元素的个数,比如我们常用的len(),就是通过这个魔法方法实现的。

__getitem__(self, key):这个方法得到了一个key,应当返回一个value。

__setitem__(self, key, value):这个方法定义了一个key和一个value,用于键值对的定义。

__delitem__(self, key):这个方法定义了使用del的时候,会进行怎么样的处理

另外,一般来说,错误的键应当引发TypeError异常,而错误的索引应当引发IndexError异常

使用方法

在python的列表中,只能够使用数字作为索引,如果使用字符串的数字的话,那么会引发异常。因此,我们可以尝试一下,对原始的列表进行扩充,使其可以接受字符串作为列表的索引。

class XiaList:
    """
    作者:瞎老弟
    时间:2021-10-26
    说明:实现了一种伪列表,可以同时接受字符串索引和数字索引
    联系方式:qq1413274264
    """
    def __init__(self, old_list):
        self.num = len(old_list)
        self.list = old_list
 
    def __len__(self):
        return self.num
 
    def __getitem__(self, key):
        try:
            k = int(key)
            return self.list[k]
        except:
            raise TypeError
 
    def __setitem__(self, key, value):
        try:
            k = int(key)
            self.old_list[key] = value
        except:
            raise TypeError
 
if __name__ == "__main__":
    x = XiaList([1, 2, 3, 4, 5])
    print(x[0])
    print(x["0"])
    print(x[-1])
    print(x["-1"])
    print(len(x))

注意,这样的自建列表,存在很多问题,几乎全部的关于列表的方法都不能再被使用了。

继承使用

为了解决正常列表的方法不能再被使用,我们可以考虑直接继承list,以此得到普通列表的所有方法。

class XiaList2(list):
    """
    作者:瞎老弟
    时间:2021-10-26
    联系方式:qq1413274264
    说明:使用XiaList2来获取元素时,如果元素为整数,则显示为多少万
    """
    def __init__(self, *args):
        super().__init__(*args)
 
    def __getitem__(self, key):
        if not isinstance(key, int):
            raise TypeError
        try:
            n = int(super().__getitem__(key))
            return str(n / 10000) + "万"
        except:
            return super().__getitem__(key)
 
if __name__ == "__main__":
    x = XiaList2([10000, 52000, 99999, "314125926", "abcd"])
    for i in range(len(x)):
        print(x[i])
    x.append(520000)
    print(x[-1])