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

时间:2010-11-04 00:54:56

标签: python list inheritance

我对使用python列表对象感兴趣,但功能稍有改动。特别是,我希望列表是1索引而不是0索引。 E.g:

>> 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 个答案:

答案 0 :(得分:49)

使用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)

但是,这不会改变其他列表方法的行为。例如,索引保持不变,这可能导致意外结果:

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

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

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

答案 1 :(得分:26)

相反,使用相同的方法将整数子类定义为将所有数字定义为从设置它们的减去1。瞧。

抱歉,我不得不这样做。这就像是微软将黑暗定义为标准的笑话。

答案 2 :(得分:16)

您可以通过创建一个继承自collections.MutableSequence的类来避免违反Liskov Substitution原则,该类是一个抽象类。它看起来像这样:

class MyList(collections.MutableSequence):
def __init__(self, l=[]):
    if type(l) is not list:
        raise ValueError()

    self._inner_list = l

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

def __delitem__(self, index):
    self._inner_list.__delitem__(index - 1)

def insert(self, index, value):
    self._inner_list.insert(index - 1, value)

def __setitem__(self, index, value):
    self._inner_list.__setitem__(index - 1, value)

def __getitem__(self, index):
    return self._inner_list.__getitem__(index - 1)

这里有一个问题(尽管可能还有更多)。如果您将新列表编入索引如下:

l = MyList()
l[0]

你实际上会打电话:

self._inner_list[-1]

将为您提供最后一个元素。因此,如果您希望为列表提供该功能,则必须对方法进行额外检查,并确保保留反向索引。

修改

这是新代码,我认为不应该有任何问题。

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)

答案 3 :(得分:-2)

class ListExt(list):
    def extendX(self, l):
        if l:
            self.extend(l)