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

min*_*ief 47 python inheritance list

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

>> mylist = MyList()
>> mylist.extend([1,2,3,4,5])
>> print mylist[1]
Run Code Online (Sandbox Code Playgroud)

输出应为: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
Run Code Online (Sandbox Code Playgroud)

我想问题是它self[key-1]本身正在调用它定义的相同方法.如果是这样,我如何使用list()方法而不是MyList()方法?我尝试使用super[key-1]而不是self[key-1]导致投诉TypeError: 'type' object is unsubscriptable

有任何想法吗?另外,如果你能指出一个很好的教程,那就太好了!

谢谢!

Gin*_*kas 53

使用该super()函数调用基类的方法,或直接调用该方法:

class MyList(list):
    def __getitem__(self, key):
        return list.__getitem__(self, key-1)
Run Code Online (Sandbox Code Playgroud)

要么

class MyList(list):
    def __getitem__(self, key):
        return super(MyList, self).__getitem__(key-1)
Run Code Online (Sandbox Code Playgroud)

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

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

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

print numbers[numbers.index('one')]
>>> 'two'
Run Code Online (Sandbox Code Playgroud)

  • 为什么递归发生在问题中得到了很好的解释. (9认同)
  • 另外,要小心其他列表方法,因为您正在更改索引的行为,这是列表对象的基本部分. (3认同)
  • 另外还有一点需要指出:你认为super(MyList,self)[key-1]会起作用,但事实并非如此.super()显式不适用于任何"隐式查找",如[]而不是__getitem__. (3认同)

Bin*_*ile 28

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

对不起,我不得不这样做.这就像是关于微软将黑暗定义为标准的笑话.

  • 微软将黑暗定义为标准有什么笑话?**编辑**:nvm,[找到了](https://www.ocf.berkeley.edu/~mbarrien/jokes/lightblb.txt):*“问:需要多少位微软硬件工程师来改变一个灯泡?答:没有,他们将黑暗重新定义为行业标准”* (6认同)

Ale*_*vic 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)
Run Code Online (Sandbox Code Playgroud)

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

l = MyList()
l[0]
Run Code Online (Sandbox Code Playgroud)

你会真的打电话给:

self._inner_list[-1]
Run Code Online (Sandbox Code Playgroud)

这将为您提供最后一个元素.因此,如果要为列表提供该功能,则必须对方法进行其他检查,并确保保留反向索引.

编辑:

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

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)
Run Code Online (Sandbox Code Playgroud)