Bernie Roesler
Bernie Roesler

Reputation: 358

Slicing behavior of python range()[:]

I came across an interesting bit of code in a QC review and was surprised by its behavior. I am curious if it is documented anywhere.

for i in range(0, my_array.max(), 3)[:]:
    # other code here

I was curious about the need for the [:] after range, so I tested it:

>>> range(0, 10, 3)
range(0, 10, 3)
>>> range(0, 10, 3)[:]
range(0, 12, 3)

The actual sequence defined by these ranges is identical, but I do not see this slicing behavior documented anywhere in the Python range documentation, so I was curious what is actually going on here.

Upvotes: 15

Views: 2254

Answers (2)

Primusa
Primusa

Reputation: 13498

For a moment let's pretend that range still returned a list. Slicing the range object returns a range object which would act as if you were slicing the underlying list. Instead of doing this with a list though, the range object is able to take care of it in constant time using arithmetic.

>>> range(0, 90, 2)[10:23]
range(20, 46, 2)

>>> list(range(0, 90, 2)[10:23])
[20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44]

When you do something like:

range(0, 10, 3)[:]

Python slices it with arithmetic.

My assumption is that when determining the final element it rounds up. It tries to compute the zeroth element in the range to start with. This will be start + step * 0 = 0.

Then Python tries to get the ending element. There are (10 - 0) // 3 + 1 = 4 elements in the range, so the ending element is start + step * n_elements = 0 + 3 * 4 = 12.

Upvotes: 4

9000
9000

Reputation: 40894

I think a few things are mixed here.

  • range produces slicing behavior, because slicing with non-default indexes makes sense:
>>> list(range(10, 20)[3:7])
[13, 14, 15, 16]
  • There is an idiom of copying a list (which is mutable) by producing a slice with all default indexes: some_list[:] is equivalent to something like [x for x in some_list].
  • There is the strange code that does [:] for the range object (or the actual list, if it's Python 2) which makes no sense. The generated range object / list is not referenced anywhere else anyway.
  • Python documentation lists slicing among "Common Sequence Operations" in a chapter named "Sequence Types — list, tuple, range" (emph. mine). So it's documented, but few people ever read it.

Upvotes: 1

Related Questions