Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify a Default Offset for Python List

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
like image 589
SiAce Avatar asked Apr 23 '26 14:04

SiAce


2 Answers

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.

like image 162
Moinuddin Quadri Avatar answered Apr 26 '26 05:04

Moinuddin Quadri


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.

like image 21
Prune Avatar answered Apr 26 '26 05:04

Prune



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!