If you are asking for a specific index then you are telling the computer that your code requires the value to proceed. Therefore, there must be an element at the specified index or you will see the error. When using this method it is common practice to check first, for example:
value = None
if len(s) > 0:
value = s[0] # if index 0 doesn't exist, and error will be thrown
If you are asking for an open ended "slice" like that then you are telling the computer that you want all elements in a specified range. You the programmer will need to handle the possible outcomes: no elements exist, 1 element exists, more than one element exists.
values = s[:0] # returns variable number of elements
if len(values) == 0:
...
elif len(values) > 0:
...
Both methods have their uses. Remember that you the programmer are in control. These are both just tools you can use to solve your issue. With each option comes different edge cases that you have to handle. Keep in mind that there are one or two appropriate data structure(s) for every scenario. If you are using an inappropriate one, like putting object properties into an array instead of using a class, you will find your code looking cumbersome and ugly. Just something to keep in mind. Stuff like this just makes sense as you get more experienced. Hope that helps!