Special case: input has a known "sentinel" value at the end, or values are known to be distinct
In this case, we can simply check for the value of the last input.
Special case: do something extra with the last element only
Python's for
loop does not create a separate scope, which is by design. Therefore, just write the "extra" code after the loop:
for element in iterable:
do_normal_thing(element)
do_extra_thing(element)
Special case: do something extra "between" each element
Often, people conceive of this problem as: do something normal and then something extra on each iteration, except skipping the extra part on the last iteration. As described in S.Lott's answer, this makes the problem too complex. It is trivial to detect the first iteration of a for
loop - for example, by using a simple flag variable - which also allows for solving the problem: do something extra and then something normal on each iteration, except skipping the extra part on the first iteration. Thus:
first = True
for element in iterable:
if first:
do_extra_thing(element)
first = False
do_normal_thing(element)
(Of course, there are cases that are even more special. For example, if "do something normal" means "append the element to an output string", and "do something extra" means "append a separator string to the output", then what we are really doing is joining up the elements with separators in between.)
Special case: handle overlapping pairs of elements
Sometimes people who need to loop over overlapping pairs of elements in the input, will conceive of this as: loop over every element except the last; for each of those elements, do something with that element and the one after it.
This is actually a very awkward way to describe the problem, because getting the "next element" from an element does not work. We need either an iterator over the input, or index values (for a sequence).
This problem is better considered as a completely different problem, which is covered in depth here: How can I iterate over overlapping (current, next) pairs of values from a list?.
General case: do something special with the last element
If the problem doesn't match either of the above special cases, it will be necessary to take a more heavy-duty approach. Here are some options:
Verify the last element by its index
If the input is a sequence (i.e., it has a known length), then it is trivial to determine the index of the last element. By accessing the index using enumerate
, then, it becomes straightforward to solve the problem. For example:
for index, element in enumerate(sequence):
if index == len(sequence) - 1:
do_something_special(element)
else:
do_something_normal(element)
Slice the input
Again if the input is a sequence, we can take a slice that contains every element but the last, iterate over that, and then handle the last element:
for element in sequence[:-1]:
do_something_normal(element)
do_something_special(sequence[-1])
This assumes that there is at least one element (otherwise, element[-1]
will raise an IndexError
). This can be handled in the usual ways (by an explicit check ahead of time, or with standard exception handling); or we can iterate over two separate slices to avoid the error:
for element in sequence[:-1]:
do_something_normal(element)
for element in sequence[-1:]:
do_something_special(element)
This works because slicing doesn't care about "missing" elements; if sequence
is empty, then sequence[-1:]
will simply be an empty list.
It's not possible to slice iterables without a definite length, because they can only be processed by looking at the elements one at a time, and simply looking at an element doesn't determine whether it's the last one. itertools.islice
cannot fix this (and therefore explicitly disallows negative values for the stop point of the slice).
Use lookahead
See the lookahead
iterator implementation in Ferdinand Beyer's answer; this allows us to write code like:
for element, is_last in lookahead(sequence):
if is_last:
do_something_special(element)
else:
do_something_normal(element)
Another implementation of this idea is Ants Aasma's answer. This basically reframes the problem as a "iterate over overlapping pairs" problem, except that a sentinel value is added so that the last value in the input has a "pair", and the loop can then simply check for that sentinel.