If you're concerned about potentially large collections built dynamically, so that you don't want to temporarily place it into a single data structure, here's a different way:
FLAGMASK_FIRST = 1
FLAGMASK_LAST = 2
def flag_lastfirst(collection):
    first_flag = FLAGMASK_FIRST
    first = True
    index = 0
    for element in collection:
        if not first:
            yield index, first_flag, current
            index += 1
            first_flag = 0
        current = element
        first = False
    if not first:
        yield index, first_flag | FLAGMASK_LAST, current
l = [1, 2, 3, 4]
for k in flag_lastfirst(l):
    print(k)
The function will produce a sequence of tuples, one for each element from the original collection.
The contents of the tuple:
- t[0]= 0-based index
- t[1]= bitwise flags, FLAGMASK_FIRST is present if the element is the first element, FLAGMASK_LAST is present if the element is the last element
- t[2]= The original element from the original collection
Sample output from the code above:
 +-- 0-based index
 v
(0, 1, 1)
(1, 0, 2)
(2, 0, 3)
(3, 2, 4)
    ^  ^
    |  +-- the element from the original collection
    |
    +-- 1 means first, 2 means last,
        3 means both first and last, 0 is everything else
I'm sure there are nicer ways to build this kinda thing, but this is my contribution anyway.