import itertools
class Indexable(object):
def __init__(self,it):
self.it = iter(it)
def __iter__(self):
return self.it
def __getitem__(self,index):
try:
return next(itertools.islice(self.it,index,index+1))
except TypeError:
return list(itertools.islice(self.it,index.start,index.stop,index.step))
Man könnte es wie folgt verwenden:
it = Indexable(fib())
print(it[10])
#144
print(it[2:12:2])
#[610, 1597, 4181, 10946, 28657]
Beachten Sie, dass it[2:12:2]
nicht [3, 8, 21, 55, 144]
zurückkehrt, da der Iterator bereits 11 Elemente vorgedrungen, weil der Aufruf von it[10]
.
Edit: Wenn Sie it[2:12:2]
möchten [3, 8, 21, 55, 144]
dann vielleicht diese zurückkehren statt:
class Indexable(object):
def __init__(self, it):
self.it = iter(it)
self.already_computed = []
def __iter__(self):
for elt in self.it:
self.already_computed.append(elt)
yield elt
def __getitem__(self, index):
try:
max_idx = index.stop
except AttributeError:
max_idx = index
n = max_idx - len(self.already_computed) + 1
if n > 0:
self.already_computed.extend(itertools.islice(self.it, n))
return self.already_computed[index]
Diese Version speichert die Ergebnisse in self.already_computed
und verwendet diese Ergebnisse wenn möglich. Andernfalls berechnet es mehr Ergebnisse, bis es ausreichend viele hat, um das indizierte Element oder die Scheibe zurückzugeben.
das gleiche Verhalten wie einer Liste zu zeigen, würde __getitem__ müssen den Generator zurückzuspulen. Gibt es einen einfachen Weg, das zu tun? –
Ich weiß nicht, ob es eine Möglichkeit gibt, dies zu tun, einfach oder nicht, aber die indexierbare Klasse könnte einfach alle bereits generierten Elemente in einer Liste speichern. Dann würde "__getitem__" die Zahlen direkt aus der Liste ziehen, nachdem der Generator bei Bedarf zuerst vorgeschoben wurde. – MatrixFrog
Danke MatrixFrog; das ist, was ich getan habe. – unutbu