Is there a way in python that you can specify a default offset for list? Like:
a = [0, 1, 2, 3, 4, 5, 6]
a.offset = 2
So that whenever use index for access/modify, the index will be added by the offset first:
a[0] == 2
a[4] == 6
There's no built-in way to achieve this. However you can create your custom class by extending list to get this behaviour. When you do my_list[n], internally __getitem__() function is triggered. You can override this function to return the value by adding offset to the index.
Similarly, list contains other magic functions which you can override to further modify the behaviour of your custom class. For example, __setitem__() is triggered when you assign any value to list, __delitem__() is trigger while deleting the item.
Here's a sample code to create OffsetList class which takes additional argument as offset while creating the list, and performs index based operations on index+offset value.
class OffsetList(list):
def __init__(self, offset, *args, **kwargs):
super(OffsetList, self).__init__(*args, **kwargs)
self.offset = offset
def _get_offset_index(self, key):
if isinstance(key, slice):
key = slice(
None if key.start is None else key.start + self.offset,
None if key.stop is None else key.stop + self.offset,
key.step
)
elif isinstance(key, int):
key += self.offset
return key
def __getitem__(self, key):
key = self._get_offset_index(key)
return super(OffsetList, self).__getitem__(key)
def __setitem__(self, key, value):
key = self._get_offset_index(key)
return super(OffsetList, self).__setitem__(key, value)
def __delitem__(self, key):
key = self._get_offset_index(key)
return super(OffsetList, self).__delitem__(key)
Sample Run:
# With offset as `0`, behaves as normal list
>>> offset_list = OffsetList(0, [10,20,30,40,50,60])
>>> offset_list[0]
10
# With offset as `1`, returns index+1
>>> offset_list = OffsetList(1, [10,20,30,40,50,60])
>>> offset_list[0]
20
# With offset as `2`, returns index+2
>>> offset_list = OffsetList(2, [10,20,30,40,50,60])
>>> offset_list[0]
30
# Slicing support, with `start` as start+offset and `end` as end+offset
>>> offset_list[1:]
[40, 50, 60]
# Assigning new value, based on index+offset
>>> offset_list[0] = 123
>>> offset_list
[10, 20, 123, 40, 50, 60]
# Deleting value based on index+offset
>>> del offset_list[0]
>>> offset_list
[10, 20, 40, 50, 60]
Similarly you can modify the behaviour of other magic functions like __len__(), __iter__(), __repr__(), __str__(), etc as per your need.
There is no such feature in Python -- or in any other language that I know of. Your suggested syntax is reasonable, assuming that you could get the feature approved. However, it has several drawbacks.
Until and unless this feature became common usage, you would confuse anyone trying to read such code. Zero-based and one-based indexing are the "rule"; arbitrary indexing is a violation of long-learned assumptions.
You would seriously crimp Python's right-end indexing: the semantics aren't clear. If someone writes a[-1] to access the last element, should they get that element (this is a language-defined idiom), the original a[1] element (per your definition), a "reflective" a[-3], or index out of bounds trying to move two elements to the right?
Note that Python does give you the capability to define your own functionality:
class
Any time you don't like the given data types, you get to make your own. You're not allowed to alter the built-in types, but you can do what you like by inheriting from list and writing your own get and other methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With