用于检测空序列的更好的for循环语法?

时间:2010-12-29 19:42:15

标签: python syntax for-loop

有没有更好的方法来编写以下内容:

   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 个答案:

答案 0 :(得分: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

为一般情况引入空序列的特殊情况似乎错误。对于特定领域的问题,应该有更好的解决方案。

答案 1 :(得分: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,你也无法检查序列的bool值是否为True,原因相同。

因此,你的方式很简单 - 另一种方法是在“for”语句之前删除名称“item” 在循环之后检查它是否存在:

del item
for item in sequence:
    # do stuff
try:
    item
except NameError:
     # sequence is empty.

但是你的代码应该比它更明确。

答案 2 :(得分: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 :(得分:1)

这不应该触发len()

def handle_items(items):
    index = -1
    for index, item in enumerate(items):
        print 'processing item #%d: %r' % (index, item)
    # at this point, index will be the offset of the last item,
    # i.e. length of items minus one
    if index == -1:
        print 'there were no items to process'
    print 'done'
    print

# test with an empty generator and two generators of different length:
handle_items(x for x in ())
handle_items(x for x in (1,))
handle_items(x for x in (1, 2, 3))

答案 4 :(得分:0)

if not iterable_sequence.__length_hint__():
    empty()
else:
    for item in iterable_sequence:
        dostuff()