Python enumerate downwards or with a custom step

Here is an idiomatic way to do that:

list(zip(itertools.count(10,-2), 'abc'))

returns: [(10, 'a'), (8, 'b'), (6, 'c')]


One option is to zip your iterable to a range:

for index, item in zip(range(10, 0, -2), ['a', 'b', 'c']):
    ...

This does have the limitation that you need to know how far the range should go (the minimum it should cover - as in my example, excess will be truncated by zip).

If you don't know, you could roll your own "infinite range" (or just use itertools.count) and use that:

>>> def inf_range(start, step):
    """Generator function to provide a never-ending range."""
    while True:
        yield start
        start += step

        
>>> list(zip(inf_range(10, -2), ['a', 'b', 'c']))
[(10, 'a'), (8, 'b'), (6, 'c')]

I haven't found more elegant, idiomatic, and concise way, than to write a simple generator:

def enumerate2(xs, start=0, step=1):
    for x in xs:
        yield (start, x)
        start += step

Examples:

>>> list(enumerate2([1,2,3], 5, -1))
[(5, 1), (4, 2), (3, 3)]
>>> list(enumerate2([1,2,3], 5, -2))
[(5, 1), (3, 2), (1, 3)]

If you don't understand the above code, read What does the "yield" keyword do in Python? and Difference between Python's Generators and Iterators.