Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom OrderedDict that returns itself

I have the following custom class:

class MyArray (OrderedDict):
    def __init__ (self,*args):
        OrderedDict.__init__(self,*args)
    def __getitem__ (self, key):
        if not hasattr (key, '__iter__'):
            return OrderedDict.__getitem__ (self,key)
        return MyArray((k,self[k]) for k in key)

This class does exactly what i want for when i have multiple keys, but doesn't do what i want for single keys.

Let me demonstrate what my code outputs:

x = MyArray()

x[0] = 3
x[1] = 4
x[2] = 5

print x[1,0,2]

MyArray([(1,4),(0,3),(2,5)])

But then:

print x[1]

4

I want it to be:

MyArray([(1,4)])

Here was my attempt to fix it to act the way i want (which led to infinite recursion):

class MyArray (OrderedDict):
    def __getitem__ (self, key):
        if not hasattr (key, '__iter__'):
            return MyArray({key:OrderedDict.__getitem__ (self,key)})
        return MyArray((k,OrderedDict.__getitem__ (self,k)) for k in key)
like image 369
snowleopard Avatar asked Dec 16 '15 01:12

snowleopard


1 Answers

The key here is to realize that self[k] is the same as self.__getitem__(k) so you don't want to use self[k] inside __getitem__, unless you are in fact trying to do some recursion. Instead always use OrderedDict.__getitem__ (self,key).

On an unrelated note, you generally don't want to create a method that just calls the same method of the parent class, ie:

class MyArray (OrderedDict):
    def __init__ (self,*args):
        OrderedDict.__init__(self,*args)

Just delete the method and python will call the parent class method for you, inheritance is awesome :).

update:

After some digging I found that you get infinite recursion when you try to print a MyArray because OrderedDict.__repr__ calls OrderDict.items which then calls OrderDict.__getitem__ (in the form of self[key]), then it calls __repr__ on each of the items ... The issue here is that you're modifying __getitem__ to do something very different than what it does in the Parent class. If you want this class to have the full functionality of a python class, you'll need to override every method that uses self[key] anywhere in the method. You can start with items, ie something like:

def items(self):
    'od.items() -> list of (key, value) pairs in od'
    return [(key, OrderedDict.__getitem__(self, key)) for key in self]

When you hit this kind of thing it's often better to drop the subclassing and just have the OrderedDict be an attribute of the new class, something like:

class MyArray(object):

    def __init__(self, *args):
        self.data = OrderedDict(*args)

    def __getitem__(self, key):
        if not hasattr (key, '__iter__'):
            return MyArray([(key, self.data[key])])
        return MyArray([(k, self.data[k]) for k in key])
like image 131
Bi Rico Avatar answered Oct 16 '22 18:10

Bi Rico