如何在Python中继承和扩展列表对象?

75 投票
4 回答
79416 浏览
提问于 2025-04-16 06:31

我想使用Python的列表对象,但希望它的功能稍微有所不同。具体来说,我希望这个列表是从1开始计数,而不是从0开始。例如:

>> mylist = MyList()
>> mylist.extend([1,2,3,4,5])
>> print mylist[1]

输出应该是:1

但是当我修改了__getitem__()__setitem__()这两个方法来实现这个功能时,我遇到了一个RuntimeError: maximum recursion depth exceeded的错误。我对这两个方法进行了很多尝试,但基本上就是我在里面写的这些:

class MyList(list):
    def __getitem__(self, key):
        return self[key-1]
    def __setitem__(self, key, item):
        self[key-1] = item

我想问题出在self[key-1]这个调用上,它实际上是在调用它自己定义的方法。如果是这样的话,我该如何让它使用list()方法,而不是MyList()方法呢?我试着用super[key-1]代替self[key-1],但结果出现了TypeError: 'type' object is unsubscriptable的错误。

有没有什么好的建议?另外,如果你能推荐一个好的教程,那就太好了!

谢谢!

4 个回答

27

你可以通过创建一个从 collections.MutableSequence 这个抽象类继承的类来避免违反 里氏替换原则。这个类大概是这样的:

def indexing_decorator(func):
    def decorated(self, index, *args):
        if index == 0:
            raise IndexError('Indices start from 1')
        elif index > 0:
            index -= 1
        return func(self, index, *args)
    return decorated


class MyList(collections.MutableSequence):
    def __init__(self):
        self._inner_list = list()

    def __len__(self):
        return len(self._inner_list)

    @indexing_decorator
    def __delitem__(self, index):
        self._inner_list.__delitem__(index)

    @indexing_decorator
    def insert(self, index, value):
        self._inner_list.insert(index, value)

    @indexing_decorator
    def __setitem__(self, index, value):
        self._inner_list.__setitem__(index, value)

    @indexing_decorator
    def __getitem__(self, index):
        return self._inner_list.__getitem__(index)

    def append(self, value):
        self.insert(len(self) + 1, value)
34

相反,你可以通过创建一个整数的子类,来定义所有数字比你设置的值少一。这样就搞定了。

抱歉,我不得不这么说。这就像是一个关于微软的笑话,说他们把黑色定义为标准色。

75

使用 super() 函数可以调用父类的方法,或者你也可以直接调用这个方法:

class MyList(list):
    def __getitem__(self, key):
        return list.__getitem__(self, key-1)

或者

class MyList(list):
    def __getitem__(self, key):
        return super(MyList, self).__getitem__(key-1)

不过,这样做不会改变其他列表方法的行为。例如,索引(index)还是保持不变,这可能会导致一些意想不到的结果:

numbers = MyList()
numbers.append("one")
numbers.append("two")

print numbers.index('one')
>>> 1

print numbers[numbers.index('one')]
>>> 'two'

撰写回答