4

I am trying to define a default style list object:

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

It works.

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

But I think it's terrible to query my ilist. I've tried the following method:

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)

but the fact shows it totally equals self[n] and causes RuntimeError: maximum recursion depth exceeded

I also tried to borrow the parent class list method .But the form isx.__getitem__(y). I don't know how to adapt it to ilist.

So finally my terrible solution comes out. Raw and brute force..Is there any effecient or simple solution? Thanks in advance.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
tcpiper
  • 2,456
  • 2
  • 28
  • 41
  • 3
    Well... the error's obvious... but it might be worth explaining what you're actually trying to achieve... What you've got so far just looks a mess and I'm not sure what you really want... – Jon Clements Oct 30 '13 at 14:49
  • Actually, that is what I really want. I didn't know there exists such a powerful menthod `super` in overriding some basic methods. Oh I guess this is why it is called `super`... – tcpiper Oct 30 '13 at 15:16

3 Answers3

7

Use super() to access the original __getitem__:

def __getitem__(self,n):
    while len(self) <= n:
        self.append(self.dft)
    return super(ilist, self).__getitem__(n)

Demo:

>>> 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

You probably want to support slicing as well:

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)

and if you wanted to support assignment to arbitrary indices as well, add a __setitem__ method:

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)

but then you could move the default-value creation out to a helper method:

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)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
1

After appending the necessary number of elements, you can simply call the original (overridden) __getitem__ method as follows.

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
Eser Aygün
  • 7,794
  • 1
  • 20
  • 30
0

Martijn's answer ready to use and w/o errors:

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)
leonhma
  • 110
  • 9