>>> range(1,11)
gives you
[1,2,3,4,5,6,7,8,9,10]
Why not 1-11?
Did they just decide to do it like that at random or does it have some value I am not seeing?
>>> range(1,11)
gives you
[1,2,3,4,5,6,7,8,9,10]
Why not 1-11?
Did they just decide to do it like that at random or does it have some value I am not seeing?
Basically in python
range(n)
iteratesn
times, which is of exclusive nature that is why it does not give last value when it is being printed, we can create a function which gives inclusive value it means it will also print last value mentioned in range.Although there are some useful algorithmic explanations here, I think it may help to add some simple 'real life' reasoning as to why it works this way, which I have found useful when introducing the subject to young newcomers:
With something like 'range(1,10)' confusion can arise from thinking that pair of parameters represents the "start and end".
It is actually start and "stop".
Now, if it were the "end" value then, yes, you might expect that number would be included as the final entry in the sequence. But it is not the "end".
Others mistakenly call that parameter "count" because if you only ever use 'range(n)' then it does, of course, iterate 'n' times. This logic breaks down when you add the start parameter.
So the key point is to remember its name: "stop". That means it is the point at which, when reached, iteration will stop immediately. Not after that point.
So, while "start" does indeed represent the first value to be included, on reaching the "stop" value it 'breaks' rather than continuing to process 'that one as well' before stopping.
One analogy that I have used in explaining this to kids is that, ironically, it is better behaved than kids! It doesn't stop after it supposed to - it stops immediately without finishing what it was doing. (They get this ;) )
Another analogy - when you drive a car you don't pass a stop/yield/'give way' sign and end up with it sitting somewhere next to, or behind, your car. Technically you still haven't reached it when you do stop. It is not included in the 'things you passed on your journey'.
I hope some of that helps in explaining to Pythonitos/Pythonitas!
Exclusive ranges do have some benefits:
For one thing each item in
range(0,n)
is a valid index for lists of lengthn
.Also
range(0,n)
has a length ofn
, notn+1
which an inclusive range would.It works well in combination with zero-based indexing and
len()
. For example, if you have 10 items in a listx
, they are numbered 0-9.range(len(x))
gives you 0-9.Of course, people will tell you it's more Pythonic to do
for item in x
orfor index, item in enumerate(x)
rather thanfor i in range(len(x))
.Slicing works that way too:
foo[1:4]
is items 1-3 offoo
(keeping in mind that item 1 is actually the second item due to the zero-based indexing). For consistency, they should both work the same way.I think of it as: "the first number you want, followed by the first number you don't want." If you want 1-10, the first number you don't want is 11, so it's
range(1, 11)
.If it becomes cumbersome in a particular application, it's easy enough to write a little helper function that adds 1 to the ending index and calls
range()
.Consider the code
The idea is that you get a list of length
y-x
, which you can (as you see above) iterate over.Read up on the python docs for range - they consider for-loop iteration the primary usecase.
It's also useful for splitting ranges;
range(a,b)
can be split intorange(a, x)
andrange(x, b)
, whereas with inclusive range you would write eitherx-1
orx+1
. While you rarely need to split ranges, you do tend to split lists quite often, which is one of the reasons slicing a listl[a:b]
includes the a-th element but not the b-th. Thenrange
having the same property makes it nicely consistent.