Поскольку вы спрашивали о дизайне, я напишу немного о том, что вы хотите - это не итератор.
Определяющим свойством итератора является то, что он только поддерживает итерацию, а не произвольный доступ. Но такие методы, как .first
и .last
, осуществляют произвольный доступ, поэтому вы запрашиваете не итератор.
Конечно, есть контейнеры, которые позволяют это. Они называются последовательностями, и самый простой из них - list
. Это .first
метод записывается как [0]
, а .last
это [-1]
.
Итак, вот такой объект, который разрезает заданную последовательность. Он хранит список slice
объектов, который Python использует для вырезания частей списка. Методы, которые класс должен реализовать, чтобы быть последовательностью, определяются базовым классом abstact Sequence
. Хорошо наследовать от него, потому что он выдает ошибки, если вы забыли реализовать требуемый метод.
from collections import Sequence
class SlicedList(Sequence):
def __init__(self, iterable, size):
self.seq = list(iterable)
self.slices = [slice(i,i+size) for i in range(0,len(self.seq), size)]
def __contains__(self, item):
# checks if a item is in this sequence
return item in self.seq
def __iter__(self):
""" iterates over all slices """
return (self.seq[slice] for slice in self.slices)
def __len__(self):
""" implements len( .. ) """
return len(self.slices)
def __getitem__(self, n):
# two forms of getitem ..
if isinstance(n, slice):
# implements sliced[a:b]
return [self.seq[x] for x in self.slices[n]]
else:
# implements sliced[a]
return self.seq[self.slices[n]]
s = SlicedList(range(100), 5)
# length
print len(s) # 20
#iteration
print list(s) # [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], ... , [95, 96, 97, 98, 99]]
# explicit iteration:
it = iter(s)
print next(it) # [0, 1, 2, 3, 4]
# we can slice it too
print s[0], s[-1] # [0, 1, 2, 3, 4] [95, 96, 97, 98, 99]
# get the first two
print s[0:2] # [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
# every other item
print s[::2] # [[0, 1, 2, 3, 4], [10, 11, 12, 13, 14], [20, 21, 22, 23, 24], ... ]
Теперь, если вам действительно нужны такие методы, как .start
(что в любом случае, просто подробный способ для [0]
), вы можете написать класс, подобный этому:
class Navigator(object):
def __init__(self, seq):
self.c = 0
self.seq = seq
def next(self):
self.c +=1
return self.seq[self.c]
def prev(self):
self.c -=1
return self.seq[self.c]
def start(self):
self.c = 0
return self.seq[self.c]
def end(self):
self.c = len(self.seq)-1
return self.seq[self.c]
n = Navigator(SlicedList(range(100), 5))
print n.start(), n.next(), n.prev(), n.end()