问题描述
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 等。