Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a simple way to override the list object's method __getitem__? [duplicate]

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.

like image 556
tcpiper Avatar asked Oct 20 '25 01:10

tcpiper


2 Answers

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)
like image 76
Martijn Pieters Avatar answered Oct 21 '25 16:10

Martijn Pieters


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
like image 29
Eser Aygün Avatar answered Oct 21 '25 14:10

Eser Aygün



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!