在python中调用next之前,装饰迭代器以更改值的好方法是什么?
我正在处理一个问题,涉及从统一的diff补丁中验证格式 内部格式中的变量一次可以跨越多行,因此我编写了一个生成器,它可以拉动每行并在完成时生成变量 为了避免在读取统一的diff文件时重写此函数,我创建了一个生成器,在将统一的diff字符传递给内部格式验证器之前,将其从行中剥离。然而,我陷入了一个无限循环(无论是在代码中还是在头脑中)。我已将问题抽象为以下代码。我相信有更好的办法。我只是不知道那是什么在python中调用next之前,装饰迭代器以更改值的好方法是什么?,python,validation,iterator,generator,decorator,Python,Validation,Iterator,Generator,Decorator,我正在处理一个问题,涉及从统一的diff补丁中验证格式 内部格式中的变量一次可以跨越多行,因此我编写了一个生成器,它可以拉动每行并在完成时生成变量 为了避免在读取统一的diff文件时重写此函数,我创建了一个生成器,在将统一的diff字符传递给内部格式验证器之前,将其从行中剥离。然而,我陷入了一个无限循环(无论是在代码中还是在头脑中)。我已将问题抽象为以下代码。我相信有更好的办法。我只是不知道那是什么 from collections import Iterable def inner_form
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)
有没有更好、更具python风格的方法可以做到这一点?如果您将DecoratedGenerator的定义更改为:
class DecoratedGenerator(Iterable):
def __iter__(self):
# Using iterable from closure
for outer_item in iterable:
self.outer_info = outer_item[0]
inner_item = outer_item[1:]
yield inner_item
原始版本从未终止,因为它的
next()
方法是无状态的,每次调用它时都会返回相同的值。不过,您根本不需要有next()方法——您可以自己实现\uuu iter\uuu()
(正如我所做的那样),然后一切都很好。我仍然不太喜欢这个方法,但至少它比较短,而且有点像python:
from itertools import imap, izip
from functools import partial
def inner_format_validator(inner_item):
return not inner_item.startswith('+')
inner_gen = partial(imap, inner_format_validator)
def split(astr):
return astr[0], astr[1:]
def outer_gen(iterable):
outer_stuff, inner_stuff = izip(*imap(split, iterable))
return izip(inner_gen(inner_stuff), outer_stuff)
[编辑]internal\u gen()
和outer\u gen()
不带imap和部分:
def inner_gen(iterable):
for each in iterable:
yield inner_format_validator(each)
def outer_gen(iterable):
outer_stuff, inner_stuff = izip(*(split(each) for each in iterable))
return izip(inner_gen(inner_stuff), outer_stuff)
也许这是一个更好的解决方案,尽管有所不同:
def transmogrify(iter_of_iters, *transmogrifiers):
for iters in iter_of_iters:
yield (
trans(each) if trans else each
for trans, each in izip(transmogrifiers, iters)
)
for outer, inner in transmogrify(imap(split, stuff), inner_format_validator, None):
print inner, outer
我会做一些简单的事情,比如:
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
这将只执行前4行一次,然后进入循环并产生您想要的结果
您可能希望在cacth索引器中添加一些尝试
/以外的内容
如果您想在值以某个开头或相反的开头时获取它们,请记住您可以使用itertools
工具箱中的大量内容,尤其是dropwhile
、takewhile
和chain
:
>>> 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']
请记住,您可以创建理解列表之类的生成器,将它们存储在变量中并链接它们,就像您使用管道传输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)
有了这些,您应该能够找到一些pythonic方法来解决您的问题:-)感谢您提供了如何使用functools.partial
的示例。这些工具非常漂亮,但我发现这个解决方案有点难以遵循。这样做会对性能有什么好处吗?一个问题是izip(*imap(split,iterable))
中的参数解包,它一次将整个拆分的iterable解包到内存中。请参阅我的其他解决方案,以获得避免此问题的替代方案。我觉得这很像蟒蛇。我想最后一个例子就是我要找的。