Anderson Green
Anderson Green

Reputation: 31810

Mimic JavaScript arrays in Python

In Python, is it possible to mimic JavaScript arrays (i. e., arrays that expand automatically when values are added outside the array's range)? In JavaScript, arrays expand automatically when a value is assigned outside of an array's index, but in Python, they do not:

theArray = [None] * 5
theArray[0] = 0
print(theArray)
theArray[6] = 0 '''This line is invalid. Python arrays don't expand automatically, unlike JavaScript arrays.'''

This would be valid in JavaScript, and I'm trying to mimic it in Python:

var theArray = new Array();
theArray[0] = 0;
console.log(theArray);
theArray[6] = 0; //the array expands automatically in JavaScript, but not in Python

Upvotes: 0

Views: 173

Answers (3)

Paul S.
Paul S.

Reputation: 66324

zch has already given a great answer, but I'll post this to show you how to copy behaviour for the get, too

class MyList(list):
    @property
    def length(self): # for the example bracket notation
        return len(self)
    def __getitem__(self, key): # Fix GET
        try: # assume permission
            return list.__getitem__(self, key)
        except (IndexError, TypeError): # "ask forgiveness"
            pass # using pass to save indents as try was a return
        if key == 'length': # example bracket notation for length getter
            return self.length
        try: # JavaScript doesn't care about number type and accepts
            key = int(key) # strings, too, but Python req.s integers
            return list.__getitem__(self, int(key))
        except (IndexError, ValueError):
            pass
        return None
    def __setitem__(self, key, value): # Fix SET
        try:
            list.__setitem__(self, key, value)
            return value # copy return behaviour
        except (IndexError, TypeError):
            pass
        try:
            key = int(key) # force int
        except ValueError:
            return # fail quietly?
        if key < 0: # still throw for bad key
            raise IndexError()
        self.extend((key - len(self)) * [None]) # fill gap with None
        self.append(value) # append new value
        return value # copy return behaviour

>>> a = MyList()
>>> a[0] = 1
>>> a[2] = 1
>>> (a, a[3])
([1, None, 1], None)
>>> (a.length, a['length'])
(3, 3)

Upvotes: 2

Ian
Ian

Reputation: 50905

I can't think of a native way this is implemented. Saying that, it wouldn't be a bad idea to just create a function that does what you expect. Instead of using my_list[index] = value, you could use something like:

def insertWithAutoFill(the_list, index, new_item):
    if index >= len(the_list):
        for i in range(len(the_list), index):
             the_list.append(None)
        the_list.append(new_item)
    else:
        the_list[index] = new_item

And you'd call it like:

my_list = [1, 2, 3]
insertWithAutoFill(my_list, 6, 23)

With the my_list now containing:

[1, 2, 3, None, None, None, 23]

You might have to adjust some things to make sure certain things are checked properly and index is being used properly. This was minorly tested and worked in specific cases, but it's not guaranteed to be perfect :)

Upvotes: 1

zch
zch

Reputation: 15278

If you really need you can define such structure:

class ExpandingList(list):
    def __setitem__(self, key, value):
        try:
            list.__setitem__(self, key, value)
        except IndexError:
            self.extend((key - len(self)) * [None] + [value])

>>> a = ExpandingList()
>>> a[1] = 4
>>> a
[None, 4]
>>> a[4] = 4
>>> a
[None, 4, None, None, 4]

Integrating it with other python features might be tricky (negative indexing, slicing).

Upvotes: 4

Related Questions