微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为 Python 列表指定默认偏移量

如何解决为 Python 列表指定默认偏移量

python 中有没有办法为列表指定认偏移量? 喜欢:

a = [0,1,2,3,4,5,6]
a.offset = 2

这样每当使用索引进行访问/修改时,索引将首先添加偏移量:

a[0] == 2
a[4] == 6

解决方法

Python 或我所知道的任何其他语言中都没有这样的功能。您建议的语法是合理的,假设您可以获得该功能的批准。但是,它有几个缺点。

直到并且除非此功能成为常见用法,否则您会混淆任何试图阅读此类代码的人。从零开始和从一开始的索引是“规则”;任意索引违反了长期学习的假设。

您会严重压缩 Python 的右端索引:语义不清楚。如果有人写 a[-1] 来访问最后一个元素,他们是否应该得到那个元素(这是一个语言定义的习语),原始的 a[1] 元素(根据你的定义),一个“反射”{{1 }} 或 a[-3] 试图将两个元素向右移动?


请注意,Python 确实让您能够定义自己的功能:

班级

任何时候您不喜欢给定的数据类型,您都可以创建自己的数据类型。您不能更改内置类型,但您可以通过继承 index out of bounds 并编写自己的 list 和其他方法来做您喜欢做的事情。

,

如果您只是从列表中读取数据,您可能可以使用原始的下标副本:

a = [0,1,2,3,4,5,6] 
a = a[2:]

a[0] == 2 # True
a[4] == 6 # True

请记住,这会使用相同的变量名称复制列表,因此您将丢失原始内容(索引 0 和 1)。如果确实需要,您可以将它保存在一个单独的变量中:

a = [0,6] 
a0,a = a,a[2:]

a[0] == 2 # True
a[4] == 6 # True

a0[0] == 0 # True
a0[4] == 4 # True

如果您确实需要具有读写功能的原始数组的视图,那么我建议使用 numpy 数组:

import numpy as np

a = np.array([0,6])
b = a[2:].view()

b[0] == 2  # True
b[4] == 4  # True

b[1] = 99
print(a)   # [ 0  1  2 99  4  5  6]
a[3] == 99 # True 

如果你想自己实现类似于 numpy 的东西,你可以创建一个类来表示一个列表上的“视图”,其中包含一个内部切片属性(开始、停止、步骤):

class ListView:

    def __init__(self,aList,start=None,stop=None,step=1):
        self.data   = aList
        self.slice  = slice(start,stop,step)
        
    @property
    def indices(self): return range(len(self.data))[self.slice]

    def offset(self,index=None):
        if not isinstance(index,slice): return self.indices[index]
        first = self.indices[index][0]  
        last  = self.indices[index][-1] 
        step  = (index.step or 1)*(self.slice.step or 1)
        return slice(first,last+1-2*(step<0),step)         
        
    def __len__(self): return len(self.indices)

    def __getitem__(self,index): return self.data[self.offset(index)]

    def __repr__(self): return self[:].__repr__()

    def __iter__(self): return self[:].__iter__()

    def __setitem__(self,index,value): self.data[self.offset(index)] = value

    def __delitem__(self,index): del self.data[self.offset(index)]

用法:

a = list(range(1,21))

v = ListView(a,-2,2)

len(v)  # 8

print(a) 
# [1,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

print(v) 
# [4,18]

v[2] += 80

print(a)
# [1,88,20]

v.slice = slice(-4,None,-3)
print(v)
# [17,2]
,

没有内置的方法来实现这一点。但是,您可以通过扩展 list 来创建自定义类以获得此行为。当您执行 my_list[n] 时,会触发内部 __getitem__() 功能。您可以通过将 offset 添加到索引来覆盖此函数以返回值。

同样,list 包含其他 magic functions,您可以覆盖这些 __setitem__() 以进一步修改自定义类的行为。例如,__delitem__() 为列表赋值时触发,__len__() 删除项时触发。

这是创建 OffsetList 类的示例代码,该类在创建 offset 时将附加参数作为 list,并在 index+{ 上执行基于索引的操作{1}} 值。

offset

样品运行:

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,self).__delitem__(key)

同样,您可以根据需要修改其他魔法函数的行为,例如 __iter__()__repr__()__str__()Indentation 等。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。