有没有一种简单的方法覆盖列表对象的方法__getitem__?

4
我正在尝试定义一个默认的样式列表对象:
class ilist(list):
    def __init__(self,r=list(),dft=None):
        list.__init__(self,r)
        self.dft=dft
    def __getitem__(self,n):
        if len(self)<=n:
            for i in range(n-len(self)+1):
                self.append(self.dft)
        for i,v in enumerate(self):
            if i+1==len(self):
                return v

x=ilist()
print x[4]
print x

它有效。

>>> 
None
[None, None, None, None, None]  

但我认为查询我的ilist是可怕的。

我尝试了以下方法:

def __getitem__(self,n):
    from operator import getitem
    if len(self)<=n:
        for i in range(n-len(self)+1):
            self.append(self.dft)
    return getitem(self,n)

但事实表明它完全等同于self [n],并导致RuntimeError:递归深度超过最大值。

我还尝试借用父类list的方法,但格式是x.__getitem__(y)。我不知道如何适应ilist。

所以最终我的可怕解决方案出现了。原始且粗暴...有没有更有效或简单的解决方案?提前致谢。


3
好的...错误很明显...但值得解释一下你实际想要达到什么目标...你目前所拥有的看起来很混乱,我不确定你真正想要什么... - Jon Clements
其实,这正是我想要的。我不知道在覆盖一些基本方法时存在如此强大的super方法。哦,我猜这就是为什么它被称为super的原因... - tcpiper
3个回答

7
使用 super() 来访问原始的 __getitem__ 方法:
def __getitem__(self,n):
    while len(self) <= n:
        self.append(self.dft)
    return super(ilist, self).__getitem__(n)

示例:

>>> class ilist(list):
...     def __init__(self,r=list(),dft=None):
...         list.__init__(self,r)
...         self.dft=dft
...     def __getitem__(self, n):
...         while len(self) <= n:
...             self.append(self.dft)
...         return super(ilist, self).__getitem__(n)
... 
>>> il = ilist()
>>> il[3]
>>> il
[None, None, None, None]
>>> il[2] = 5
>>> il
[None, None, 5, None]
>>> il[2]
5

您可能也希望支持切片:

def __getitem__(self, n):
    maxindex = n
    if isinstance(maxindex, slice):
        maxindex = maxindex.indices(len(self))[1]
    while len(self) <= maxindex:
        self.append(self.dft)
    return super(ilist, self).__getitem__(n)

如果您想支持对任意索引的赋值,还需要添加一个 __setitem__ 方法:

def __setitem__(self, n, val):
    maxindex = n
    if isinstance(maxindex, slice):
        maxindex = maxindex.indices(len(self))[1]
    while len(self) <= maxindex:
        self.append(self.dft)
    return super(ilist, self).__setitem__(n, val)

但是你可以将默认值的创建移动到一个辅助方法中:
class ilist(list):
    def __init__(self, r=None, dft=None):
        if r is None:
            r = []
        list.__init__(self, r)
        self.dft=dft

    def _ensure_length(n):
        maxindex = n
        if isinstance(maxindex, slice):
            maxindex = maxindex.indices(len(self))[1]
        while len(self) <= maxindex:
            self.append(self.dft)

    def __getitem__(self, n):
        self._ensure_length(n)
        return super(ilist, self).__getitem__(n)

    def __setitem__(self, n, val):
        self._ensure_length(n)
        return super(ilist, self).__getitem__(n)

1
在添加所需数量的元素后,您可以按照以下方式简单地调用原始(重写的)__getitem__方法。
class ilist(list):
    def __init__(self,r=list(),dft=None):
        list.__init__(self,r)
        self.dft=dft
    def __getitem__(self,n):
        if len(self)<=n:
            for i in range(n-len(self)+1):
                self.append(self.dft)
        return super(ilist, self).__getitem__(n)

x=ilist()
print x[4]
print x

0

Martijn的答案已经准备好并且没有错误:

class ilist(list):
    def __init__(self, r=None, dft=None):
        if r is None:
            r = []
        list.__init__(self, r)
        self.dft = dft

    def _ensure_length(self, n):
        maxindex = n
        if isinstance(maxindex, slice):
            maxindex = maxindex.indices(len(self))[1]
        while len(self) <= maxindex:
            self.append(self.dft)

    def __getitem__(self, n):
        self._ensure_length(n)
        return super(ilist, self).__getitem__(n)

    def __setitem__(self, n, val):
        self._ensure_length(n)
        return super(ilist, self).__setitem__(n, val)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接