在python中重构生成器的第一次迭代

时间:2012-10-30 07:42:39

标签: python loops refactoring

我想知道是否有办法重构以下代码

 first_run = True
 for i in gen:
        if first_run:
            last_head = i[1]
            last_tail = i[2]
            last_chrom = i[0]
            first_run = False
        else:
            func(i[1], last_head)
            func(i[1], last_tail)
            last_head = i[1]
            last_tail = i[2]
            last_chrom = i[0]

6 个答案:

答案 0 :(得分:5)

循环的基本点似乎是对迭代的连续元素对执行某些操作。所以我会查看函数pairwise,其定义在itertools module documentation

中给出
def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

请注意,这不是实际的itertools函数,您必须将实现复制并粘贴到代码中。无论如何,使用此函数,您的循环可以像这样实现:

for a, b in pairwise(gen):
    func(b[1], a[1])
    func(b[1], a[2])

答案 1 :(得分:1)

这应该简化循环

first_run = True
for i in gen:
    if first_run == False:
        func(i[1], last_head)
        func(i[1], last_tail)

     last_head, last_tail, last_chrom  = i[1], i[2], i[0]
     first_run = False

更新了答案......

答案 2 :(得分:1)

我会删除 if / else 并通过切片列表分配 - 除非 func 的参数是由它更新的对象: 如果gen是生成器:

my_gen = gen
values = my_gen.next()
last_chrom, last_head, last_tail = values[:3]
for values in my_gen:
    func(last_head, last_head)
    func(last_head, last_tail)
    last_chrom, last_head, last_tail = values[:3]

编辑: 刚注意到我的错误

答案 3 :(得分:0)

如果循环后你不需要变量last_head,last_tail和last_chrom,你可以采用这个解决方案:

for index, val in enumerate(gen[:1]):
    func(val[1], gen[index-1][1])
    func(val[1], gen[index-1][2])

答案 4 :(得分:0)

it = iter(gen) # make sure we have an iterator
_, last_head, last_tail = next(it, [None]*3) # assume iterator returns 3 values
for _, head, tail in it:
    func(head, last_head)
    func(head, last_tail)
    last_head, last_tail = head, tail

如果你不能假设迭代器一次返回3个值,那么:

it = iter(gen)
last = next(it, None)
for x in it:
    func(x[1], last[1]) # head, last_head
    func(x[1], last[2]) # head, last_tail
    last = x

您还可以使用itertools' pairwise()建议的@David食谱:

for last, x in pairwise(gen):
    func(x[1], last[1]) # head, last_head
    func(x[1], last[2]) # head, last_tail

答案 5 :(得分:0)

我最喜欢以特殊方式处理“第一项”的方法是使用break的一次性循环:

def gen():
    for x in range(5):
        yield x

def first_special(g):
    for item in g:
        print 'first', item
        break
    for item in g:
        print item

 first_special(gen())
 # prints "first 0, 1,2,3,4

请注意,这适用于单元素或空迭代器。要使first_special同时使用任意迭代,我通常会向其添加一个安全iter()调用:

def first_special(g):
    g = iter(g)
    for item in g:
        print 'first', item
        break
    for item in g:
        print item