当使用for循环迭代时,我如何处理输入的最后一个元素?特别是,如果有代码应该只出现在元素之间(而不是在最后一个元素之后),我该如何构造代码?
目前,我写的代码是这样的:
for i, data in enumerate(data_list):
code_that_is_done_for_every_element
if i != len(data_list) - 1:
code_that_is_done_between_elements
我如何简化或改进它?
我想到的最简单的解决办法是:
for item in data_list:
try:
print(new)
except NameError: pass
new = item
print('The last item: ' + str(new))
所以我们总是通过延迟处理一个迭代来提前一个项目。为了在第一次迭代中跳过某些操作,我只需捕获错误。
当然,您需要考虑一下,以便在需要时引发NameError。
还要保留“counstruct”
try:
new
except NameError: pass
else:
# continue here if no error was raised
这依赖于之前没有定义名称new。如果你是偏执狂,你可以确保new不存在,使用:
try:
del new
except NameError:
pass
当然,你也可以使用if语句(if notfirst: print(new) else: notfirst = True)。但据我所知,开销更大。
Using `timeit` yields:
...: try: new = 'test'
...: except NameError: pass
...:
100000000 loops, best of 3: 16.2 ns per loop
所以我认为开销是不可能当选的。
因此,这绝对不是“更短”的版本——如果“最短”和“Pythonic”实际上是兼容的,人们可能会离题。
但如果经常需要这种模式,就把逻辑放到a中
10行生成器-并获得与元素相关的任何元数据
在for调用中直接定位。这里的另一个优势是它会
适用于任意可迭代对象,而不仅仅是序列。
_sentinel = object()
def iter_check_last(iterable):
iterable = iter(iterable)
current_element = next(iterable, _sentinel)
while current_element is not _sentinel:
next_element = next(iterable, _sentinel)
yield (next_element is _sentinel, current_element)
current_element = next_element
In [107]: for is_last, el in iter_check_last(range(3)):
...: print(is_last, el)
...:
...:
False 0
False 1
True 2
假设input是一个迭代器,下面是使用itertools中的tee和izip的方法:
from itertools import tee, izip
items, between = tee(input_iterator, 2) # Input must be an iterator.
first = items.next()
do_to_every_item(first) # All "do to every" operations done to first item go here.
for i, b in izip(items, between):
do_between_items(b) # All "between" operations go here.
do_to_every_item(i) # All "do to every" operations go here.
演示:
>>> def do_every(x): print "E", x
...
>>> def do_between(x): print "B", x
...
>>> test_input = iter(range(5))
>>>
>>> from itertools import tee, izip
>>>
>>> items, between = tee(test_input, 2)
>>> first = items.next()
>>> do_every(first)
E 0
>>> for i,b in izip(items, between):
... do_between(b)
... do_every(i)
...
B 0
E 1
B 1
E 2
B 2
E 3
B 3
E 4
>>>