YiFei
YiFei

Reputation: 1856

How can I indexing nested lists?

When nested lists encountered in a class (more specifically, I should call it a multivariate function), can I use __getitem__ method with two or more arguments?

I know it's not the typical usage of __getitem__ and I should write it as a method of class, but I really want to take advantage of its [] feature.

Upvotes: 1

Views: 115

Answers (2)

Cody Piersall
Cody Piersall

Reputation: 8557

It's really not atypical at all; numpy does it all the time. __getitem__ accepts a single argument; it can be a tuple. You'll just have to parse the tuple yourself.

class Indexer(object):
    def __init__(self, *args, **kwargs): 
        pass
    def __getitem__(self, item):
        if isinstance(item, tuple):
            # do special processing for tuples here
            print(item)
        # Everyone likes the number 3, so make sure to return an extra 3.
        return [item, 3]
i = Indexer()

# this will print (2, 3), and got_item will have the value [(2, 3), 3]
got_item = i[2,3]

# This will print [(2, 3), 3]
print(got_item)

Obviously there's no real reason to return [item, 3], but it just demonstrates that the code inside __getitem__ can do whatever it wants. You can return anything your heart desires.

Whenever the Python interpreter sees you index something (as in i[2, 3] in the code sample), the first thing it does is build a tuple out of the stuff between the square brackets. You can check this by using the dis module, which disassembles python code to see what the interpreter is really doing:

import dis
dis.dis('a[b, c]')

  1           0 LOAD_NAME                0 (a)
              3 LOAD_NAME                1 (b)
              6 LOAD_NAME                2 (c)
              9 BUILD_TUPLE              2
             12 BINARY_SUBSCR
             13 RETURN_VALUE

If you've never seen output from dis before, it can be a little confusing. The important part is where it says BUILD_TUPLE before it says BINARY_SUBSCR.

That may be too much info: the important thing is that you can do whatever you want with __getitem__.

Upvotes: 1

jbndlr
jbndlr

Reputation: 5210

__getitem__ accepts as many arguments as you want, as they are packed as a tuple. See the following example, where the nested list inside the class is stored in _data and initialized using certain dimensions.

class Table(object):
    def __init__(self, dimx, dimy, initialize=0):
        self._dimx = dimx
        self._dimy = dimy
        self._data = [[initialize] * self._dimx] * self._dimy

    def __getitem__(self, *args):
        idx = args[0]
        return self._data[idx[0]][idx[1]]

    def __setitem__(self, *args):
        idx = args[0]
        self._data[idx[0]][idx[1]] = args[1]

With this class, you can simply perform the following:

t = Table(10, 1)
t[0, 1] = 'a'
print(t[0, 0])
print(t[0, 1])

... and it will yield:

0
a

Upvotes: 0

Related Questions