如果迭代完成但不被
else
打断,则 for
/else
子句中的 break
块将被执行,所以我读到了。
是否有一种语言构造可以让我编写一些仅在
for
循环没有开始迭代时才执行的东西?如果我使用 tuple
或 list
,我会做这样的事情:
if seq:
for x in seq:
# something
else:
# something else
但是当我使用生成器时,我没有得到我想要的行为:
>>> g = (x for x in range(2))
>>> for x in g:
... print x
... else:
... print "done"
...
0
1
done # I don't want "done" here
>>> g = (x for x in range(2) if x > 1)
>>> if g:
... for x in g:
... print x
... else:
... print "done"
...
>>> # I was expecting "done" here
我怎样才能做到这一点而不用尽全力从生成器创建
tuple
或list
,同时还使用for
循环?我可以在 next()
循环中使用 while
并尝试捕获 StopIteration
,但我想看看是否有一个很好的方法来使用 for
来做到这一点。
我想不出比在 for 循环内更新布尔值更好的方法了。
any_results = False
for x in g:
any_results = True
print x
if not any_results:
print 'Done'
n = -1
for n, i in enumerate(it):
do_stuff()
if n < 0:
print 'Done'
我发现这个解决方案更好。检查此链接以获取更多信息(http://python-notes.curiousefficiency.org/en/latest/python_concepts/break_else.html)。
您可以使用自定义哨兵: x = no_data = 对象()
x = no_data = object()
for x in data:
.......
if x is no_data:
print "Loop did not run"
object() 返回一个无特征的对象,它是所有类的基础。
检查两个对象是否相同(x 是 no_data)。如果它们保持相同,则意味着控件从未进入 for 循环。
您可以使用生成器函数:
next
接受可选的第二个参数,可用于指定默认值,以防迭代器耗尽。
def func(lis):
g = (x for x in lis if x > 1)
flag = object() # expected to be unique
nex = next(g, flag) # will return flag if genexp is empty
if nex is not flag:
yield nex
for item in g:
yield item
else:
yield "done"
for x in func(range(2)):
print x
print "------"
for x in func(range(4)):
print x
输出:
done
------
2
3
我认为了解循环是否实际执行的一个好方法是使用循环变量
lv= 1
for x in g:
lv = lv+1
print x
if (lv == 1):
print 'Done'
我的语法可能是错误的,因为我不是Python专家..
您可以编写一个包装器来计算迭代次数。它的优点是可以处理更奇特的枚举。在 python3 中,它会是这样的:
import sys
from glob import iglob
class GenCount(object):
def __init__(self, gen):
self._iter = iter(gen)
self.count = 0
def __next__(self):
val = self._iter.__next__()
self.count += 1
return val
def __iter__(self):
return self
c = GenCount(iglob(sys.argv[1]))
for fn in c:
print(fn)
print(c.count)
c = GenCount(iglob(sys.argv[1]))
print([fn for fn in c])
print(c.count)
可以检查循环中是否定义了x。
for x in (y for y in range(2) if y > 1):
print(x)
try:
print(f'do something with {x}')
except NameError:
print('the loop did not run')
但是,请确保 x 未在循环之前定义。
当
else
分支是有副作用的表达式(或表达式序列)时,可以使用布尔运算符的短路属性。例如,这个 Python 3 代码:
def print_items_or_nothing(items):
if items == []:
print("nothing")
else:
for item in items:
print(item)
print_items_or_nothing([]) # prints "nothing"
print_items_or_nothing([1, 2, 3]) # prints "1", "2", "3"
...可以重写为:
def print_items_or_nothing(items):
for item in items or print("nothing") or []:
print(item)
该技术利用了以下事实:当且仅当左侧操作数为假时,
or
才会计算并返回其右侧操作数。
考虑表达式
items or print("nothing") or []
:
items
非空,则为真,因此不计算表达式的其余部分,结果为 items
。items
为空,则为假,因此 print("nothing")
被求值...为 None
,这是假的,因此 []
被求值并构成结果,该结果是可迭代的(根据需要)。else
分支不包含指令的情况(尽管您当然可以使用海象运算符来增加不可读性);在此示例中,您需要额外的构造吗?
caught = None
for item in x:
caught = item
print caught
if caught != None: print "done"
*编辑OP评论*t