# [Python-ideas] Pass a function as the argument "step" of range()

Steven D'Aprano steve at pearwood.info
Thu Jul 2 19:14:29 CEST 2015

```On Thu, Jul 02, 2015 at 08:30:53AM +0200, Pierre Quentel wrote:
> In languages such as Javascript, the incrementation of a for loop counter
> can be done by an operation, for instance :
>
> for(i=1; i<N; i*=2)
>
> would iterate on the powers of 2 lesser than N.
>
> To achieve the same thing in Python we currently can't use range() because
> it increments by an integer (the argument "step"). An option is to build a
> generator like :
>
> def gen(N):
>     i = 1
>     while i<=N:
>         yield i
>         i *= 2

Given how simple generators are in Python, that's all you need for the
most part. If you find yourself needing to do the above many times, with
different expressions, you can write a factory:

def gen(start, end, func):
def inner():
i = start
while i < end:
yield i
i = func(i)
return inner()

for i in gen(1, 100, lambda x: 3**x - x**3):
for j in gen(-1, 5, lambda x: x**2):
for k in gen(1000, 20, lambda x: -(x**3)):
pass

> My proposal is that besides an integer, range() would accept a function as
> the "step" argument, taking the current counter as its argument and
> returning the new counter value. Here is a basic pure-Python implementation

Why add this functionality to range? It has little to do with range,
except that range happens to sometimes be used as the sequence in
for-loops. range has nice simple and clean semantics, for something as
uncommon as this request, I think a user-defined generator is fine.

range is not a tool for generating arbitrary sequences. It is a tool for
generating sequences with equal-spaced values. Let's not complicate it.

--
Steven
```