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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4093029/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 14:12:46  来源:igfitidea点击:

How to inherit and extend a list object in Python?

pythonlistinheritance

提问by mindthief

I am interested in using the python list object, but with slightly altered functionality. In particular, I would like the list to be 1-indexed instead of 0-indexed. E.g.:

我对使用 python 列表对象感兴趣,但功能略有改变。特别是,我希望列表是 1-indexed 而不是 0-indexed。例如:

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

output should be: 1

输出应为:1

But when I changed the __getitem__()and __setitem__()methods to do this, I was getting a RuntimeError: maximum recursion depth exceedederror. I tinkered around with these methods a lot but this is basically what I had in there:

但是当我更改__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

I guess the problem is that self[key-1]is itself calling the same method it's defining. If so, how do I make it use the list()method instead of the MyList()method? I tried using super[key-1]instead of self[key-1]but that resulted in the complaint TypeError: 'type' object is unsubscriptable

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

Any ideas? Also if you could point me at a good tutorial for this that'd be great!

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

Thanks!

谢谢!

采纳答案by Gintautas Miliauskas

Use the super()function to call the method of the base class, or invoke the method directly:

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

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

or

或者

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

However, this will not change the behavior of other list methods. For example, index remains unchanged, which can lead to unexpected results:

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

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

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

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

回答by Binary Phile

Instead, subclass integer using the same method to define all numbers to be minus one from what you set them to. Voila.

相反,使用相同的方法将整数子类化,以将所有数字定义为从您设置的数字减去一。瞧。

Sorry, I had to. It's like the joke about Microsoft defining dark as the standard.

对不起,我不得不。这就像微软将黑暗定义为标准的笑话。

回答by Aleksandar Jovanovic

You can avoid violating the Liskov Substitution principle by creating a class that inherits from collections.MutableSequence, which is an abstract class. It would look something like this:

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

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)

There is one problem here (though there might be more). If you index your new list like this:

这里有一个问题(尽管可能还有更多)。如果你像这样索引你的新列表:

l = MyList()
l[0]

you will actually call:

你实际上会打电话:

self._inner_list[-1]

which will get you the last element. So you must do additional checking in the methods and make sure you keep the reverse indexing, if you want to have that feature for your list.

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

EDIT:

编辑:

Here is the new code, which I believe should not have any problems.

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

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)

回答by Moisey Oysgelt

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