问题
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.
回答1:
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)
回答2:
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
来源:https://stackoverflow.com/questions/19686118/is-there-a-simple-way-to-override-the-list-objects-method-getitem