Reputation: 31810
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
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
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
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