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

Nick Coghlan ncoghlan at gmail.com
Fri Jul 3 13:23:49 CEST 2015

On 3 July 2015 at 06:20, Pierre Quentel <pierre.quentel at gmail.com> wrote:
> @Steven, Mark
> The definition of range() in Python docs says :
> Python 2.7 : "This is a versatile function to create lists containing
> arithmetic progressions. It is most often used in for loops."
> Python 3.4 : "The range type represents an immutable sequence of numbers and
> is commonly used for looping a specific number of times in for loops."

Pierre, I *wrote* the Python 3 range docs. I know what they say.
Functionality for generating an arbitrary numeric series isn't going
into range().

Now, it may be that there's value in having a way to neatly express a
potentially infinite mathematical series, and further value in having
a way to terminate iteration of that series based on the values it

The key question you need to ask yourself is whether or not you can
come up with a proposal that is easier to read than writing an
appropriately named custom iterator for whatever iteration problem you
need to solve, or using a generator expression with
itertools.takewhile and itertools.count:

    from itertools import takewhile, count
    for i in takewhile((lambda i: i < N), (2**x for x in count())):

Outside obfuscated code contests, there aren't any prizes for
expressing an idea in the fewest characters possible, but there are
plenty of rewards to be found in expressing ideas in such a way that
future maintainers can understand not only what the code actually
does, but what it was intended to do, and that the computer can also
execute at an acceptable speed.

Assuming you're able to come up with such a proposal, the second
question would then be whether that solution even belongs in the
standard library, let alone in the builtins. What are the real world
problems that the construct solves that itertools doesn't already
cover? Making it easier to translate homework assignments written to
explore features of other programming languages rather than features
of Python doesn't count.

> Both stress that range is most often used in a for loop (it doesn't "happens
> to sometimes be used" in for loops, and is rarely used for membership
> testing). Python 2.7 limited its definition to arithmetic progressions, but
> Python 3.4 has a more general definition (an immutable sequence of numbers).
> I really don't think that the proposal would change the general idea behind
> range : a suite of integers, where each item is built from the previous
> following a specific pattern, and stopping when a "stop" value is reached.

There isn't a "general idea" behind Python 3's range type, there's a
precise, formal definition.

For starters, the contents are defined to meet a specific formula:
For a positive step, the contents of a range r are determined by the
formula r[i] = start + step*i where i >= 0 and r[i] < stop.

For a negative step, the contents of the range are still determined by
the formula r[i] = start + step*i, but the constraints are i >= 0 and
r[i] > stop.

If you're tempted to respond "we can change the formula to use an
arbitrary element value calculation algorithm", we make some *very*
specific performance and behavioural promises for range objects, like:

Range objects implement the collections.abc.Sequence ABC, and provide
features such as containment tests, element index lookup, slicing and
support for negative indices
Testing range objects for equality with == and != compares them as
sequences. That is, two range objects are considered equal if they
represent the same sequence of values. (Note that two range objects
that compare equal might have different start, stop and step
attributes, for example range(0) == range(2, 1, 3) or range(0, 3, 2)
== range(0, 4, 2).)


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-ideas mailing list