使用range
实际上并不难实现。您可以对范围进行切片,它会为您完成所有复杂的算术运算:
>>> range(20)[10:]
range(10, 20)
>>> range(10, 20)[::2]
range(10, 20, 2)
>>> range(10, 20, 2)[::-3]
range(18, 8, -6)
所以你只需要一个包含对原始序列引用和范围的对象类。这是这样一个类的代码(希望不会太大):
class SequenceView:
def __init__(self, sequence, range_object=None):
if range_object is None:
range_object = range(len(sequence))
self.range = range_object
self.sequence = sequence
def __getitem__(self, key):
if type(key) == slice:
return SequenceView(self.sequence, self.range[key])
else:
return self.sequence[self.range[key]]
def __setitem__(self, key, value):
self.sequence[self.range[key]] = value
def __len__(self):
return len(self.range)
def __iter__(self):
for i in self.range:
yield self.sequence[i]
def __repr__(self):
return f"SequenceView({self.sequence!r}, {self.range!r})"
def __str__(self):
if type(self.sequence) == str:
return ''.join(self)
elif type(self.sequence) in (list, tuple):
return str(type(self.sequence)(self))
else:
return repr(self)
这是在大约5分钟内拼凑出来的,因此在将其用于任何重要场合之前,请务必进行彻底测试。
用法:
>>> p = list(range(10))
>>> q = SequenceView(p)[3:6]
>>> print(q)
[3, 4, 5]
>>> q[1] = -1
>>> print(q)
[3, -1, 5]
>>> print(p)
[0, 1, 2, 3, -1, 5, 6, 7, 8, 9]
* 在 Python 3 中
memoryview
仅适用于具有缓冲区接口的对象,而列表不是其中之一。 - zegkljanbytearray
而不是列表。您还可以将列表包装在bytearray
中。 - robertmemoryview
文档没有链接到它,因此请参考缓冲区协议。 - Kevin J. Chase