在 python 中调用 next 之前装饰迭代器以更改值的好方法是什么?
我正在解决一个问题,涉及验证统一差异补丁中的格式。
内部格式中的变量可以一次跨越多行,因此我编写了一个生成器,它提取每一行并在完成时生成变量。
为了避免在从统一差异文件读取时必须重写此函数,我创建了一个生成器,在将其传递到内部格式验证器之前从该行中去除统一差异字符。然而,我陷入了无限循环(无论是在代码中还是在我的脑海中)。我已将问题抽象为以下代码。我确信有更好的方法来做到这一点。我只是不知道那是什么。
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化的方法有什么想法吗?
I am working on a problem that involves validating a format from within unified diff patch.
The variables within the inner format can span multiple lines at a time, so I wrote a generator that pulls each line and yields the variable when it is complete.
To avoid having to rewrite this function when reading from a unified diff file, I created a generator to strip the unified diff characters from the line before passing it to the inner format validator. However, I am getting stuck in an infinite loop (both in the code and in my head). I have abstracted to problem to the following code. I'm sure there is a better way to do this. I just don't know what it is.
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)
Any ideas as to a better, more pythonic way to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我会做一些更简单的事情,如下所示:
这将仅执行前 4 行一次,然后进入循环并产生您想要的结果。
您可能想在 cacth
IndexErrors
各处添加一些try
/except
。如果您想在值开始时获取值或相反,请记住您可以使用
itertools
工具箱中的很多内容,特别是dropwhile
、takewhile
和chain
:记住,您可以创建像理解列表这样的生成器,将它们存储在变量中并将它们链接起来,就像您通过管道传输 Linux 命令一样:
有了这一切,您应该能够找到一些Python式的方法来解决你的问题:-)
I would do something simpler, like this:
This will execute the 4 first lines only once, then enter the loop and yield what you want.
You probably want to add some
try
/except
to cacthIndexErrors
here and there.If you want to take values while they start with something or the contrary, remember you can use a lot of stuff from the
itertools
toolbox, and in particulardropwhile
,takewhile
andchain
:And remember that you can create generators like comprehension lists, store them in variables and chain them, just like you would pipe linux commands:
With all this, you should be able to find some pythonic way to solve your problem :-)
我仍然不太喜欢这个,但至少它更短,更Pythonic:
[编辑]
inner_gen()
和outer_gen()
没有 imap 和部分:也许这是一个更好但不同的解决方案:
I still don't like this very much, but at least it's shorter and a tad more pythonic:
[EDIT]
inner_gen()
andouter_gen()
without imap and partial:Maybe this is a better, though different, solution:
我认为,如果您将 DecoratedGenerator 的定义更改为:
您的原始版本永远不会终止,因为它的 next() 方法是无状态的,并且每次调用时都会返回相同的值。不过,您根本不需要 next() 方法——您可以自己实现 __iter__() (就像我所做的那样),然后一切正常。
I think it will do what you intended if you change the definition of DecoratedGenerator to this:
Your original version never terminated because its
next()
method was stateless and would return the same value every time it was called. You didn't need to have a next() method at all, though--you can implement__iter__()
yourself (as I did), and then it all works fine.