使用Python索引和切割生成器

Jas*_*sta 29 python generator

假设我有一个生成器函数,如下所示:

def fib():
    x,y = 1,1
    while True:
        x, y = y, x+y
        yield x
Run Code Online (Sandbox Code Playgroud)

理想情况下,我可以使用fib()[10]fib()[2:12:2]来获取索引和切片,但是目前我必须使用itertools来处理这些事情.我无法使用生成器来替换列表.

我相信解决方案是将fib()包装在一个类中:

class Indexable(object):
    ....

fib_seq = Indexable(fib())
Run Code Online (Sandbox Code Playgroud)

Indexable应该如何使其工作?

unu*_*tbu 34

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))
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

it = Indexable(fib())
print(it[10])
#144
print(it[2:12:2])
#[610, 1597, 4181, 10946, 28657]
Run Code Online (Sandbox Code Playgroud)

请注意,由于调用了迭代器已经提升了11个元素,因此it[2:12:2]不会返回.[3, 8, 21, 55, 144]it[10]

编辑:如果你想it[2:12:2]返回,[3, 8, 21, 55, 144]那么也许使用它:

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]
Run Code Online (Sandbox Code Playgroud)

此版本会保存结果self.already_computed并尽可能使用这些结果.否则,它会计算更多结果,直到它有足够多的结果来返回索引元素或切片.