Why are slice and range upper-bound exclusive? Why are slice and range upper-bound exclusive? python python

Why are slice and range upper-bound exclusive?


The documentation implies this has a few useful properties:

word[:2]    # The first two charactersword[2:]    # Everything except the first two characters

Here’s a useful invariant of slice operations: s[:i] + s[i:] equals s.

For non-negative indices, the length of a slice is the difference of the indices, if both are within bounds. For example, the length of word[1:3] is 2.

I think we can assume that the range functions act the same for consistency.


Here's the opinion of some Google+ user:

[...] I was swayed by the elegance of half-open intervals. Especially the invariant that when two slices are adjacent, the first slice's end index is the second slice's start index is just too beautiful to ignore. For example, suppose you split a string into three parts at indices i and j -- the parts would be a[:i], a[i:j], and a[j:].

Google+ is closed, so link doesn't work anymore. Spoiler alert: that was Guido van Rossum.


Elegant-ness VS Obvious-ness

To be honest, I thought the way of slicing in Python is quite counter-intuitive, it's actually trading the so called elegant-ness with more brain-processing, that is why you can see that this StackOverflow article has more than 2Ks of upvotes, I think it's because there's a lot of people don't understand it intially.

Just for example, the following code had already caused headache for a lot of Python newbies.

x = [1,2,3,4]print(x[0:1])# Output is [1]

Not only it is hard to process, it is also hard to explain properly, for example, the explanation for the code above would be take the zeroth element until the element before the first element.

Now look at Ruby which uses upper-bound inclusive.

x = [1,2,3,4]puts x[0..1]# Output is [1,2]

To be frank, I really thought the Ruby way of slicing is better for the brain.

Of course, when you are splitting a list into 2 parts based on an index, the exclusive upper bound approach would result in better-looking code.

# Pythonx = [1,2,3,4]pivot = 2print(x[:pivot]) # [1,2]print(x[pivot:]) # [3,4]

Now let's looking the inclusive upper bound approach

# Rubyx = [1,2,3,4]pivot = 2puts x[0..(pivot-1)] # [1,2]puts x[pivot..-1] # [3,4]

Obviously, the code is less elegant, but there's not much brain-processing to be done here.

Conclusion

In the end, it's really a matter about Elegant-ness VS Obvious-ness, and the designers of Python prefer elegant-ness over obvious-ness. Why? Because the Zen of Python states that Beautiful is better than ugly.