检测空序列的更好for循环语法?
有没有更好的方法来写下面的代码:
row_counter = 0
for item in iterable_sequence:
# do stuff with the item
counter += 1
if not row_counter:
# handle the empty-sequence-case
请注意,我不能使用 len(iterable_sequence),因为 1) 不是所有的序列都有已知的长度;2) 在某些情况下,调用 len() 可能会导致序列的项目被加载到内存中(比如 SQL 查询结果的情况)。
我之所以问这个,是因为我很好奇有没有更简洁、更符合习惯的写法。我想要的写法大概是这样的:
for item in sequence:
#process item
*else*:
#handle the empty sequence case
(假设这里的“else”只对空序列有效,虽然我知道实际上并不是这样)
5 个回答
2
J.F. Sebastian的第二个例子似乎是用while循环来解决问题的好方法。
NoItem = object()
myiter = (x for x in range(10))
item = next(myiter, NoItem)
if item is NoItem:
...
else:
while item is not NoItem:
print item
item = next(myiter, NoItem)
虽然不是最简洁的写法,但客观上来说是最清晰的……有点复杂,对吧?
3
这可能是用到 itertools.tee 的时候了。你在验证的时候“触发”了序列,但之后你会有一个未被修改的序列副本:
from itertools import tee
check, sequence = tee(sequence, 2)
try:
check.next():
except StopIteration:
#empty sequence
for item in sequence:
#do stuff
值得注意的是,tee
在这里做了“正确”的事情:当你执行 check.next()
时,它只会加载序列的第一个元素,而这个第一个元素会在 sequence
中保持可用。剩下的元素只会在 for
循环中被取出。
或者说得简单点:如果你不能使用 len,你就无法检查序列是否有布尔值为 True,原因是一样的。
所以,你的方式看起来简单得多——另一种方法是在 for
语句之前删除“item”这个名字,然后在循环结束后检查它是否存在:
del item
for item in sequence:
# do stuff
try:
item
except NameError:
# sequence is empty.
但你的代码应该被使用,因为它比这个更清晰。
8
for item in iterable:
break
else:
# handle the empty-sequence-case here
或者
item = next(iterator, sentinel)
if item is sentinel:
# handle the empty-sequence-case here
在每种情况下,如果有一个项目,它会被消耗掉。
在评论中提到的empty_adapter()
的实现示例:
def empty_adaptor(iterable, sentinel=object()):
it = iter(iterable)
item = next(it, sentinel)
if item is sentinel:
return None # empty
else:
def gen():
yield item
for i in it:
yield i
return gen()
你可以这样使用它:
it = empty_adaptor(some_iter)
if it is not None:
for i in it:
# handle items
else:
# handle empty case
为一个通用情况引入一个空序列的特殊情况似乎是不太对劲的。应该有更好的解决方案来处理特定领域的问题。