It is a numbering convention in many (nearly all?) computer languages, and, yes, you could just accept it and move on, but consider: what if you didn’t know how long the list was?
Well, the example I showed - that the length of the list is compatible with thart second index - is enough for me, but between the two of us, we have only two votes against many decades of computer programming syntax.
So, better get used to it. Having learned and used the rule for awhile, the “logic” will look a bit different to you.
Good question, I think it is/was explained why this happens in the Python 2 material. Not sure whether it’s also in the Python 3 stuff.
Anyway, please refer to the Python Docs, specifically note 4 under Common Sequence Operations.
s[i:j]
slice of s from i to j
(3)(4)
If i or j is negative, the index is relative to the end of sequence s : len(s) + i or len(s) + j is substituted. But note that -0 is still 0 .
The slice of s from i to j is defined as the sequence of items with index k such that i <= k < j . If i or j is greater than len(s) , use len(s) . If i is omitted or None , use 0 . If j is omitted or None , use len(s) . If i is greater than or equal to j , the slice is empty.
Hope that explains why you’re seeing that behaviour.
Yes, because len(letters) is 7, not 6. You can always make use of that without needing to count anything. The length of the list will always give you the correct second index for a slice, or when using range().
I am pretty new to coding, so take what I say with a grain of salt. I had the same question as you, but then I thought about it a different way:
Imagine that your list (letters ‘a’ to ‘g’) is printed in one row on a piece of paper. You then want to use a pair of scissors to cut letters ‘b’ to ‘f’ out of your list. You will then have a new paper list that only has the letters ‘b’ to ‘f.’
Then imagine that you are trying to precisely explain this to someone who doesn’t understand letters or why they are important to you, but is able to recognize what they are (e.g. like a small child). You have to tell them exactly where to make each cut. To keep things simple, you tell them to cut before a specific letter for each cut. So, going back to our example, you would tell them to cut before the letter ‘b’ and before the letter ‘g.’ That would result in a paper list of ‘b’ through ‘f.’
Now, going back to our code, the computer is like our small child who can recognize the letters, but doesn’t understand what they mean to us. We have to tell it precisely where to slice (cut) our list. So, we tell it to cut before index 1 and before index 6, which will result in our list ['b', 'c', 'd', 'e', 'f'].
Could be so that [:4] = first 4 elements of a list and [-4:] = last 4 elements of a list. That consistency between selecting first n and last n elements in a list gives some value to doing it the way they did.
Or maybe there’s some technical reason hardly anyone knows about.
The way I think about it is letters[1:6] = letters[start of included index: start of excluded index]
I am not sure either, but if I were to speculate I would guess it has to do with statistics. In Stats we learn that in order to find a range of a data series or sequence, we subtract the highest value against the lowest value in the data series. eg, say you have the following:
1, 2, 3, 4, 7, 9
in this case the Highest value is 9 and the lowest value is 1, therefore the range would be 8. So if you were to compare this with the way range and length are calculated you may see possibly why it’s so.
One way to remember how slices work is to think of the indices
as pointing *between* characters, with the left edge of the first
character numbered 0. Then the right edge of the last character
of a string of n characters has index n, for example:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
There’s more useful info on slicing in that document (it’s the tutorials on the Python site itself) so have a wee view if you wanted more info.
I think of it this way. I imagine slicing the list just before each of the two numbers, leaving you with the desired section of the list.
An alternative convention would be to slice just before the first number, and just after the second number, which I see nothing with other than being a little inconsistent.
I think maybe it’s so we can compensate for the 0-index of the lists without resorting to n-1 and do this cleanly, as in the next lesson, for instance:
If we want to select the first n elements of a list, we could use the following code:
For anyone still struggling with this convention, I find that relating it to video editing can help.
If you are editing a short video that has all the shots lined up: shot 1, shot 2, shot 3; but you want to keep shot 1 and 2 only, you would need to place your cutter (slicing tool) on the 1st frame of shot 3. If you slice at the end of shot 2, you will get shot 3 + 1 frame of shot 2. So, you really need to start cutting for the 1st frame of the next shot, leaving shot 1 and shot 2 intact.
Not sure if it helps unless people have experience in video editing, but hopefully it does.
That is telling enough so long as we recognize 0 as the first index. (If we don’t by now, we’ve been sleeping.)
Clearly, [1:6] is excluding the first index so there will only be five items in the slice.
>>> 'abcdefghijklmnopqrstuvwxyz'[1:6]
'bcdef'
>>>
At any length, you are right to have some doubt as long as you rectify it before carrying forward. That is good. Your interpretation is well grounded and meaningful. Take something away from this one.