在python中调用next之前修改迭代器以改变值的好方法是什么?

Jef*_*May 5 python validation iterator generator decorator

我正在研究一个涉及在统一差异补丁中验证格式的问题.

内部格式中的变量一次可以跨越多行,因此我编写了一个生成器来拉动每一行并在变量完成时生成变量.

为了避免在从统一的diff文件中读取时必须重写此函数,我创建了一个生成器,用于在将行传递给内部格式验证器之前从行中剥离统一的diff字符.但是,我陷入了无限循环(在代码和我的脑海中).我已将问题抽象为以下代码.我确信有更好的方法可以做到这一点.我只是不知道它是什么.

from collections import Iterable

def inner_format_validator(inner_item):
    # Do some validation to inner items
    return inner_item[0] != '+'

def inner_gen(iterable):
    for inner_item in iterable:
        # Operates only on inner_info type data
        yield inner_format_validator(inner_item)

def outer_gen(iterable):
    class DecoratedGenerator(Iterable):
        def __iter__(self):
            return self
        def next(self):
            # Using iterable from closure
            for outer_item in iterable:
                self.outer_info = outer_item[0]
                inner_item = outer_item[1:]
                return inner_item
    decorated_gen = DecoratedGenerator()
    for inner_item in inner_gen(decorated_gen):
        yield inner_item, decorated_gen.outer_info

if __name__ == '__main__':    
    def wrap(string):
        # The point here is that I don't know what the first character will be
        pseudo_rand = len(string)
        if pseudo_rand * pseudo_rand % 2 == 0:
            return '+' + string
        else:
            return '-' + string

    inner_items = ["whatever"] * 3
    # wrap screws up inner_format_validator
    outer_items = [wrap("whatever")] * 3
    # I need to be able to
    # iterate over inner_items
    for inner_info in inner_gen(inner_items):
        print(inner_info)
    # and iterate over outer_items
    for outer_info, inner_info in outer_gen(outer_items):
        # This is an infinite loop
        print(outer_info)
        print(inner_info)
Run Code Online (Sandbox Code Playgroud)

有关更好,更pythonic方式的任何想法吗?

e-s*_*tis 2

我会做一些更简单的事情,像这样:

def outer_gen(iterable):

    iterable = iter(iterable)
    first_item = next(iterable)
    info = first_item[0]

    yield info, first_item[1:]

    for item in iterable:
        yield info, item
Run Code Online (Sandbox Code Playgroud)

这将只执行前 4 行一次,然后进入循环并产生您想要的结果。

您可能想在cacth 中到处添加一些try/ 。exceptIndexErrors

如果您想在它们从某些东西开始或相反时获取值,请记住您可以使用工具箱中的很多东西itertools,特别是dropwhile, takewhilechain

>>> import itertools
>>> l = ['+foo', '-bar', '+foo']
>>> list(itertools.takewhile(lambda x: x.startswith('+'), l))
['+foo']
>>> list(itertools.dropwhile(lambda x: x.startswith('+'), l))
['-bar', '+foo']
>>> a = itertools.takewhile(lambda x: x.startswith('+'), l)
>>> b = itertools.dropwhile(lambda x: x.startswith('+'), l)
>>> list(itertools.chain(a, b))
['+foo', '-bar', '+foo']
Run Code Online (Sandbox Code Playgroud)

请记住,您可以创建像理解列表这样的生成器,将它们存储在变量中并将它们链接起来,就像通过管道传输 Linux 命令一样:

import random

def create_item():
    return random.choice(('+', '-')) + random.choice(('foo', 'bar'))

random_items = (create_item() for s in xrange(10))
added_items = ((i[0], i[1:]) for i in random_items if i.startswith('+'))
valid_items = ((prefix, line) for prefix, line in added_items if 'foo' in line)

print list(valid_items)
Run Code Online (Sandbox Code Playgroud)

有了这一切,你应该能够找到一些Python式的方法来解决你的问题:-)