I'm curious in Python why x[0]
retrieves the first element of x
while x[-1]
retrieves the first element when reading in the reverse order. The syntax seems inconsistent to me since in the one case we're counting distance from the first element, whereas we don't count distance from the last element when reading backwards. Wouldn't something like x[-0]
make more sense? One thought I have is that intervals in Python are generally thought of as inclusive with respect to the lower bound but exclusive for the upper bound, and so the index could maybe be interpreted as distance from a lower or upper bound element. Any ideas on why this notation was chosen? (I'm also just curious why zero indexing is preferred at all.)

- 995
- 2
- 10
- 23
-
4Probably because `-0 == 0` – NightShadeQueen Aug 05 '15 at 02:44
-
That's correct, but the minus sign is telling Python where to start counting and not to literally find an element with a negative index, no? – dsaxton Aug 05 '15 at 02:53
-
No, -0 is literally 0, the minus sign is an artifact of our representation of numbers less than 0. Also read about [Two's Complement](http://stackoverflow.com/a/1049774/2904896), it explains how -1 effectively maps to the largest unsigned number, which you can think of as an alias to the final element of a list. – metatoaster Aug 05 '15 at 02:55
-
If you do `a = -1` and then `x[a]` it will work the same as `x[-1]`. Which is why the `x[-0]` syntax wouldn't work without a real negative zero concept embedded in the number system somehow. – Blorgbeard Aug 05 '15 at 03:02
4 Answers
The case for zero-based indexing in general is succinctly described by Dijkstra here. On the other hand, you have to think about how Python array indexes are calculated. As the array indexes are first calculated:
x = arr[index]
will first resolve and calculate index
, and -0
obviously evaluates to 0
, it would be quite impossible to have arr[-0]
to indicate the last element.
y = -0 (??)
x = arr[y]
would hardly make sense.
EDIT:
Let's have a look at the following function:
def test():
y = x[-1]
Assume x
has been declared above in a global scope. Now let's have a look at the bytecode:
0 LOAD_GLOBAL 0 (x)
3 LOAD_CONST 1 (-1)
6 BINARY_SUBSCR
7 STORE_FAST 0 (y)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
Basically the global constant x
(more precisely its address) is pushed on the stack. Then the array index is evaluated and pushed on the stack. Then the instruction BINARY_SUBSCR
which implements TOS = TOS1[TOS]
(where TOS
means Top of Stack
). Then the top of the stack is popped into the variable y
.
As the BINARY_SUBSCR
handles negative array indices, and that -0
will be evaluated to 0
before being pushed to the top of the stack, it would take major changes (and unnecessary changes) to the interpreter to have arr[-0]
indicate the last element of the array.

- 1,742
- 11
- 15
-
The index is not taken literally with negative indices though, is it? Suppose I have a list with a 5 elements. Are we then claiming that -1 = 4 since x[4] and x[-1] refer to the same element? x[-0] would just mean begin at the end and treat the last element as the new reference point. – dsaxton Aug 05 '15 at 02:55
-
Python will add the length of the array to the index if it is negative when the array access is actually done. – M. Shaw Aug 05 '15 at 02:57
-
The Dijkstra argument is interesting, but if we think in terms of integers instead of natural numbers then we don't have to worry about having bounds that are outside the set. And since his point is pretty much about aesthetics, why can't we just decide right off the bat that the "non-strict / strict" convention is the uglier one? – dsaxton Aug 05 '15 at 04:22
-
@dsaxton We're talking about numbering - it would be quite confusing to start numbering with negative integers. As stated in Wikipedia: `In mathematics, the natural numbers (sometimes called the whole numbers) are those used for **counting and ordering**.` I'm not quite sure what you mean by the 'non-strict/strict' convention. – M. Shaw Aug 05 '15 at 04:28
-
Its mostly for a couple reasons:
- Computers work with 0-based numbers
- Older programming languages used 0-based indexing since they were low-level and closer to machine code
- Newer, Higher-level languages use it for consistency and the same reasons
For more information: https://en.wikipedia.org/wiki/Zero-based_numbering#Usage_in_programming_languages

- 142
- 6
In many other languages that use 0-based indexes but without negative index implemented as python, to access the last element of a list (array) requires finding the length of the list and subtracting 1 for the last element, like so:
items[len(items) - 1]
In python the len(items)
part can simply be omitted with support for negative index, consider:
>>> items = list(range(10))
>>> items[len(items) - 1]
9
>>> items[-1]
9

- 17,419
- 5
- 55
- 66
In python: 0 == -0
, so x[0] == x[-0]
.
Why is sequence indexing zero based instead of one based? It is a choice the language designer should do. Most languages I know of use 0 based indexing. Xpath uses 1 based for selection.
Using negative indexing is also a convention for the language. Not sure why it was chosen, but it allows for circling or looping the sequence by simple addition (subtraction) on the index.

- 478
- 2
- 8