4

Okay, I'm sure this question is a bit trivial, but I'm curious!

In python, it is completely legal to do this:

a = [1,2,3,4,5]
print(a[:123])

>> [1, 2, 3, 4, 5]

but as soon as you try to do this:

a = [1,2,3,4,5]
print(a[123])

>> IndexError: list index out of range

Why is this so, in the context of how it is stored in memory and interpreted by the compiler?

I have tried storing the first example in a variable and checking the length of that variable but it is simply the length of the original list, ignoring the subsequent empty places.

I'm genuinely curious and interested to see what the answers are!

  • Perhaps looking at [github.com/python/cpython/blob/master/Objects/sliceobject.c](https://github.com/python/cpython/blob/master/Objects/sliceobject.c) would be helpful? – RoadRunner Dec 12 '18 at 07:37
  • simple, in the first one you are saying give me anything where the position ranges from the beginning to pos 123, whereas in the second you are asking for a value at 123 index which is not there – iamklaus Dec 12 '18 at 07:37
  • 1
    I have no problem conceptualizing what an obvious result for `a[:123]` should be, but what would you want as the result of `a[123]`? – timgeb Dec 12 '18 at 07:38
  • Because it's useful! For example, truncate input to first 50 characters `foo[:50]`, get last 20 characters of something `bar[-20:]`. It's much nicer when you still get the result on short strings :) At the same time, if `alist[123]` had to return something even for a short list, what would that be? what type? Python doesn't like to guess :) – Dima Tisnek Dec 12 '18 at 08:37
  • 1
    Without this reduction to the list bounds one would have to do it manually each time and would write `foo[:50]` as `foo[:min(len(foo),50)]` and `bar[-20:]` as `bar[max(0, len(bar)-20):]`. – Dan D. Dec 12 '18 at 08:54

3 Answers3

2

This defines your list with 5 elements

a = [1,2,3,4,5]

This tells you need to start from start to 124th index of the list

>> print(a[:123])
>> [1, 2, 3, 4, 5]

You are right in asking why this does not give a segmentation fault or some memory error as this statement should be illegal. There is no 123rd or 124th index. Python here will start from the beginning and continue iterating until either:-

  1. Maximum index (123) is reached OR
  2. List items run out

In other words, If you ask C to walk 123 steps and there is an edge of cliff after 5 steps, C will jump off the cliff but Python will not

In case of

print(a[123])

You are not iterating from start but asking to jump directly to 123rd step. In this case both C and Python will crash with their own cry (IndexError or Segmentation Fault)

0

The syntax for slicing in Python 3.x follows as so,

a[start:end:step]

You can also use slicing in different ways, for example,

a[start:end]
a[start:]
a[:end]
a[:]

Setting the 'end' variable as something larger than the length of the list works because regardless of what you set 'end' to, slicing an array will always end at len(a) - 1 (Or at a[0] if you set 'step' to something negative, making the slice return the array reversed)

Answering why: List slicing creates a new list. It copies from the beginning to position 123, which doesn't exist, that's why it just slices to the known end. It seems the python devs decided to make the slicing robust, meaning it doesn't throw an error if you provide an index out of range, instead they just assume you want it to the actual end of the list. To absolutely concretely confirm that notion you'll have to ask the maintainer of the code ;)

Borisu
  • 828
  • 7
  • 15
  • Whilst true, this doesn't actually answer the question of *why* this behaviour is so. – SiHa Dec 12 '18 at 07:59
0

A simple answer will be that this is handled in the code.

While slicing if you are providing start or end values which are greater than the size of list, then it will be overwritten by last index of the list.

and when you look for exact index, it finds the index in the list, if not present it will show "Index out of range".

Sach
  • 904
  • 8
  • 20