尝试循环空可迭代时采取行动的惯用方法
假设我正在循环遍历一个可迭代对象,并且希望在迭代器为空时执行一些操作。我能想到的两种最好的方法是:
for i in iterable:
# do_something
if not iterable:
# do_something_else
第一个
empty = True
for i in iterable:
empty = False
# do_something
if empty:
# do_something_else
取决于可迭代对象是一个集合(当可迭代对象传递到循环所在的函数/方法中时非常无用),第二个集合empty,这看起来很难看。
我是否缺少另一种方法,或者第二种选择是最好的吗?如果我可以在循环语句中添加一些子句来为我处理这个问题,就像 else
使 not_found
标志消失一样,那就太酷了。
我并不是在寻找聪明的黑客。
我不是在寻找涉及大量代码的解决方案,
而是在寻找简单的语言功能。 我正在寻找一种清晰和pythonic方法来迭代可迭代对象,并在可迭代对象为空时采取一些操作,任何有经验的Python程序员都会理解。如果我可以在每次迭代时不设置标志的情况下做到这一点,那就太棒了。 如果没有简单的习语可以做到这一点,那就忘记它吧。
Suppose that I am looping over a iterable and would like to take some action if the iterator is empty. The two best ways that I can think of to do this are:
for i in iterable:
# do_something
if not iterable:
# do_something_else
and
empty = True
for i in iterable:
empty = False
# do_something
if empty:
# do_something_else
The first depends on the the iterable being a collection (so useless for when the iterable gets passed into the function/method where the loop is) and the second sets empty
on every pass through the loop which seems ugly.
Is there another way that I'm missing or is the second alternative the best? It would be really cool if there was some clause that I could add to the loop statement that would handle this for me much like else
makes not_found
flags go away.
I am not looking for clever hacks.
I am not looking for solutions that involve a lot of code
I am looking for a simple language feature.
I am looking for a clear and pythonic way to iterate over an iterable and take some action if the iterable is empty that any experienced python programmer will be understand. If I could do it without setting a flag on every iteration, that would be fantastic.
If there is no simple idiom that does this, then forget about it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我认为这是最干净的方法:
I think this the the cleanest way to do this:
这是相当黑客的,但是您可以删除
i
,然后检查它在循环后是否存在(如果不存在,则循环从未发生过):我认为这可能比仅使用标志更难看
This is quite hackish, but you can delete
i
and then check if it exists after the loop (if not, the loop never happened):I think that's probably uglier than just using a flag though
更新2
我喜欢Odomontois 的回答。恕我直言,它比我下面写的更适合这个问题。
更新
(阅读OP的评论和编辑的问题后)你也可以这样做。参见下文:
原始答案
有趣的问题。我做了一些实验并得出以下结论:
Update 2
I liked Odomontois' answer. IMHO it is better suited to this problem than what I have written below.
Update
(After reading the OP's comment and edited question) You can do that too. See below:
Original Answer
Interesting problem. I did some experiments and came up with the following:
如果要在使用迭代器之前对其进行部分检查,一般方法是使用 itertools.tee。这样我们就可以拥有迭代器的两个副本,并检查一个副本是否为空,同时仍然从一开始就消耗另一个副本。
StopIteration
异常必然是调用it1.next()
的结果,因为循环内部引发的任何StopIteration
异常都会终止该循环。编辑:对于那些不喜欢此类异常的人,可以使用
islice
来设置单步循环:我个人更喜欢第一种风格。 YMMV。
The general way forward if an iterator is to be partially checked before being consumed is to use
itertools.tee
. This way we can have two copies of the iterator and check one for emptiness while still consuming the other copy from the start.The
StopIteration
exception is bound to be a result of the call toit1.next()
, as anyStopIteration
exceptions raised froom inside the loop will terminate that loop.Edit: for those who don't like such exceptions,
islice
can be used to set up a single step loop:I personally prefer the first style. YMMV.
反转“if”和“for”怎么样:
好吧,这不起作用!
这是另一个解决方案:http://code.activestate.com/recipes/413614-testing-for-an-empty-iterator/
What about reversing "if" and "for":
OK, this does not work!
Here is an other solution: http://code.activestate.com/recipes/413614-testing-for-an-empty-iterator/
这是 迈克尔·莫罗泽克和FM的回答:
This is a combination of Michael Mrozek's and FM's answers:
生成器有一个“gi_frame”属性,一旦生成器耗尽,该属性为 None,但仅在 StopIteration 引发后才为 None。如果可以接受,您可以尝试以下方法:
Generators have a 'gi_frame' property which is None once the generator is exhausted, but only after StopIteration has been raised. If that's acceptable, here's something you could try: