Welcome, guest | Sign In | My Account | Store | Cart

The following recite shows a small addition to the tuple, list, and dictionary classes to allow for a simpler way to retrieve a number of independant items. By allowed for the subscripting to use tuples some very annoying cases becomes much simpler.

Python, 67 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class mylist(list):
    def __getitem__(self, item):
        r = []
        if type(item) == tuple:
                for i in item:
                    if type(i) == slice:
                        r.extend(super(self.__class__, self).__getitem__(i))
                    else:
                        r.append(super(self.__class__, self).__getitem__(i))
                return r
        else:
                return super(mylist, self).__getitem__(item)

    def __setitem__(self, item, value):
        if type(item) == tuple:
                for i, val in zip(item, value):
                    super(self.__class__, self).__setitem__(i, val)
        else:
                super(self.__class__, self).__setitem__(item, value)
        


class mytuple(tuple):
    def __getitem__(self, item):
        r = []
        if type(item) == tuple:
                for i in item:
                    if type(i) == slice:
                        r.extend(super(self.__class__, self).__getitem__(i))
                    else:
                        r.append(super(self.__class__, self).__getitem__(i))
                return r
        else:
                return super(mylist, self).__getitem__(item)



# Not a good idea, is tuple a key or a set of keys?
class mydict(dict):
    def __getitem__(self, item):
        r = []
        if type(item) == tuple:
                for i in item:
                        r.append((super(self.__class__, self).__getitem__(i)))
                return r
        else:
                return super(mylist, self).__getitem__(item)

# Examples
l = mylist(range(0,10))
t = mytuple(range(0,10))
d = mydict({'1':'one', '2':'two', '3':'three', '4':'four', '5':'five'})

print l[0,-1]        # Get only the first and last item
                     # [ l[0], l[-1] ]
print l[1,3:]        # Get item 1 and items 3 till the end
                     # [ l[1] ] + l[3:]
print l[1,5,7,2,3]   # Get items 1, 5, 7, 2 and 3
                     # [ l[1], l[5], l[7], l[2], l[3] ]
l[0,1:] = None, [] # Setting the first element of the list to None and removeing the rest
print l              # l[0], l[1:] = None, []
            

print t[:,0,:]  # Get the tuple twice qith the first element in between
                # t + (t[0],) + t
print t[:,::-1] # Get the tuple twice, once foreward and once reversed
                # t + t[::-1]

This is great for large data sets where you need alot of very specific items, but it becomes very annoying to type each subscript seperatly and add the lists up. It is also much clearer this way. This script also supports writing elements 'in bulk'.

I initially created the mydict for simmilar usage for dictionaries, but I later realised that it is not a good idea since there is no way to differentiate between a key which is a tuple and a tuple holding a number of keys.

I would like to know if people think that the way to set items in bulk in the list is intuitive and not confusing.

4 comments

Randy 19 years, 6 months ago  # | flag

super() use in class mytuple and mydict? Is the first parameter to super() correct in the mytuple and mydict classes? Thanks for sharing this!

Yair Chuchem 18 years, 8 months ago  # | flag

nice. but confusing for numarray users. In Numeric/numarray, ar[5,7] would be the element in the two dimensional position (5,7), and etc. For someone used to numarray, like me, seeing code using your mytuple would be rather confusing.

Edward Loper 18 years, 5 months ago  # | flag

Re: super() use in class mytuple and mydict? Randy wrote:

Is the first parameter to super() correct in the mytuple and mydict classes? Thanks for sharing this!

No, it's not, but the problem won't show up until you try to subclass it. In general, using self.__class__ as the first argument to super() is a Very Bad Idea. Here's a quick example. We start with this:

class A(object):
    def f(self,x): print x
class B(A):
    def f(self,x): super(self.__class__,self).f(x+1)

Which appears to work just fine. But then we subclass B, we get trouble:

class C(B):
    def f(self,x): super(self.__class__,self).f(x+2)

Now, when we call C().f(5), we get a maximum recursion error. Why? Because the call to super(self.__class__,self) in B finds the superclass of self relative to self.__class__. But self.__class__ is C. So it returns B.

Bottom line: you should always specify the class containing a method explicitly when using super -- if it could be done automatically, then that first argument wouldn't be there. :)

Don Sawatzky 13 years, 5 months ago  # | flag

Great use of Python OO to take care of a particular need. But for very large numbers of calls for subsets, calculations will be bog down due to the overhead of instantiation and calling these class methods. Usually for Python, a better solution is to develop functions for specific cases in busy applications.

I find, for example, that s[:2] + s[-2:] is much faster than l[:2,-2:].

Created by Daniel Brodie on Wed, 22 Sep 2004 (PSF)
Python recipes (4591)
Daniel Brodie's recipes (5)

Required Modules

  • (none specified)

Other Information and Tasks