恢复列表读取并记住光标

时间:2015-03-22 09:00:20

标签: python

当标志设置为False时,我试图使列表暂时无法读取。也就是说,当标志为False时读取列表没有给出任何值(就好像它是空的或列表已经用完)。一旦它回到True,列表就会再次变为可读,并且光标从最后停止的位置继续。我当前的实现继续读取,但不记得光标以前的位置。有谁知道如何改变它?我知道我可以有一个变量来跟踪光标的位置,但是有更优雅的方式吗?

items = range(0, 5)
flag = True

def values():
    for v in items:
        while not flag:
            yield None
        yield v

def read():
    for i in values():
        if i is None:
            return
        yield i

def run():
    global flag
    # should print just 0 1 2, as flag is False when i == 2
    for i in read():
        if i == 2:
            flag = False
        print i

    print "flip!"

    # should print just 3 4, as the previous cursor position should be used
    flag = True
    for i in read():
        print i

run() # outputs 0 1 2 flip 0 1 2 3 4 rather than the expected 0 1 2 flip 3 4

4 个答案:

答案 0 :(得分:2)

您的第一个循环正常,您可以在第一个print "**********"循环后添加for来查看结果。

但是对于第二个循环,你有一个错误的理解,因为在第二个循环中你不能从你转换falgFalse的那个部分迭代你的列表!第二个循环将从开始开始,因此您可以将第一个循环中最后一个元素的索引保存到indx变量并将其传递给您的函数:

items = range(0, 5)
flag = True

def values(indx):
    for v in items[indx:]:
        while not flag:
            yield None
        yield v

def read(indx=0):
    for i in values(indx):
        if i is None:
            return
        yield i

def run():
    global flag
    global indx
    # should print just 0 1 2
    for i,j in enumerate(read(),1):
        if j == 2:
            flag = False
            indx=i
        print j
    print "**********"

    # should print just 3 4
    flag = True
    for i in read(indx):
        print i
    print '********'
run() 

结果:

0
1
2
**********
3
4
********

答案 1 :(得分:1)

你不能用发电机做你想做的事;生成器是专门的迭代器,迭代器只能通过迭代一次。一旦他们筋疲力尽(StopIterator已被提出),他们就不能产生更多的物品。

另一方面,您的代码需要引发StopIteration(第一个循环结束),然后第二个循环继续再次迭代。

而不是在生成器中处理它,只是停止迭代。创建生成器一次,然后在两个循环中使用它:

def run():
    iterator = read()
    for i in iterator:
        print i
        if i == 2:
            break   # stop iterating

    print 'flip'

    # resume iterating
    for i in iterator:
        print i

答案 2 :(得分:1)

这样做会从根本上打破according the Python's iterator protocol

  

协议的目的是一旦迭代器的next()方法引发StopIteration,它将继续在后续调用中这样做。不遵守此属性的实现被视为已损坏。

你应该做的是将它作为一个类并将索引存储为实例变量。这样您就不必传入参数或依赖全局变量。

答案 3 :(得分:0)

您可能会在下面找到感兴趣的发电机。使用生成器的send()方法,我们可以将数据发送回生成器。有关此功能的详细信息,请参阅Python文档中的Yield expressions。 (该文档的Python 3版本为here)。

#!/usr/bin/env python

def latched_iter(iterable):
    ''' Yield items from iterable only when latch is True '''
    latch = False
    while True:
        latch = yield iterable.next() if latch else None


def main():
    gen = latched_iter(iter('abcdefghijklmnop'))
    gen.send(None)

    for i in xrange(25):
        try:
            val = gen.send(i < 5 or i >= 10)
        except StopIteration:
            break
        print i, val


if __name__ == '__main__':
    main()

<强>输出

0 a
1 b
2 c
3 d
4 e
5 None
6 None
7 None
8 None
9 None
10 f
11 g
12 h
13 i
14 j
15 k
16 l
17 m
18 n
19 o
20 p