s = "Worldoftanks" 

Why print(s[0:len(s)]) work?

len(s) will return 12 . Then it turns out s[0:12] , and this is a mistake: a call to a nonexistent index.

    3 answers 3

    For a start it is worth noting that everything is correct. From the documentation (Sequences section):

    a[i:j] returns all elements with index k such that i <= k < j . Note that j strictly greater. The last Worldoftanks index is 11 (numbering from zero) and the slice [0:len(obj)] returns all elements with indices 0 1 2 ... 10 11 equality 11 <12 is fulfilled. However, there is another point:

    The slices are separate objects that are returned by the slice function. The definition states that when a slice is taken in the normal way ([start: stop: step]), objects of this type are used implicitly. When it is necessary to return the result of the slice, the permissible boundaries will be calculated (the boundaries will be checked for you, yes), so as not to go beyond the limits. The indices method ( getIndices in CPython ) is responsible for this. You can rewrite the index taking a bit like this:

     slic = slice(0, 20) print("Тип объекта из функции slice:", type(slic)) my_string = "Hello world" print("Корректные индексы:", slic.indices(len(my_string))) print("Результат среза", my_string[slic]) >>> Тип объекта из функции slice: <class 'slice'> >>> Корректные индексы: (0, 11, 1) >>> Результат среза Hello world 

    As you can see, no errors, because indices returned the correct boundaries.

    • It is necessary to explicitly mention (repeat) that "a"[:10] works, and not just "a"[:1] , while "a"[10] and "a"[1] call IndexError (with a simple whole index, not a slice, only "a"[0] , "a"[-1] works for len(s) == 1 ) - jfs
    • looking at the source code in CPython, the lines call the PySlice_GetIndicesEx() function for slices , which normalizes indices (unlike PySlice_GetIndices() , which throws an error if the indices go out of the border). - jfs

    s [0:12] - this is from zero to 11;

    the first index is that we start what we need, the second one where we start what we do NOT need; somehow so on the docks eaten to remember, so as not to be confused)))

    UPD: in general, the slice syntax (they are also “slices”) does NOT cause errors when going beyond the array / string, as opposed to referring to a single element. well i s [100] will cause an error, and s [100: 101] will not cause it anymore, just like s [100:], and so on.

    The docks clearly stated this: docs.python.org/2/tutorial/introduction.html , we are looking for the line "However, out of range slice indexes are handled gracefully when used for slicing"

    • The fact is that s[0:188] - also works great for this string - andy.37
    • one
      By the way, yes, the departure of the cut-off range beyond does not cause errors. for example, s [100: 110] will return an empty string, not an error. he himself even forgot)) - AlexandrX
    • one
      In general, the slice syntax never causes errors until the indices are integers. But in the documentation I can not dig it. - andy.37
    • one
      yes no, at the docks it is clearly stated, for example. here: docs.python.org/2/tutorial/introduction.html , search for the line "However, out of range slice indexes are handled gracefully when used for slicing". Kakraz after your comment on my answer went there, without practice, such nuances quickly fly out of my head -))) - AlexandrX
    • I would add this in response. - andy.37

    Why print(s[0:len(s)]) work?

    The right cut edge is the same as for range(len(s)) in Python does not turn on :

     >>> [*range(4)] [0, 1, 2, 3] 

    It can be seen that the right border 4 excluded. Similarly, print(s[0:len(s)]) prints all characters with valid indices from 0 to len(s) - 1 inclusive, that is, in the range 0 <= i < len(s) . EW Dijkstra explains (in 1982) why the right border should not be included.

    In fact, for strings ( str type) and other standard sequences in Python, you can use in slices values ​​outside the permissible indexes , for example:

     'a'[-42:1000] 

    does not throw an error, since s[i:j] formal :

    (4) For example, 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.

    (3) If i or j is negative, the index is relative to the end of the sequence: s (len (s) + i or len (s) + j is cho. But note that -0 is still 0.

    If the indices are negative, then len(s) is added to them and then s[i:j] equivalent to :

     s[max(0, min(i, len(s))) : max(0, min(j, len(s)))] 

    that is, i, j are forced to the range [0, len(s)] (both ends inclusive) are given.

    Unspecified bounds or None are replaced with 0 and len(s) respectively: s[0:len(s)] == s[:] == s . If, as a result, i >= j , then an empty slice is created.

    Illustration from introductory manual :

      +---+---+---+---+---+---+ | P | y | t | h | o | n | +---+---+---+---+---+---+ 0 1 2 3 4 5 6 -6 -5 -4 -3 -2 -1 

    "Python"[3:5] == "ho" —visually it suffices to select the letters ( 'h' and 'o' ) that are between the specified indices ( 3 and 5 ).

    s[i:j] acts like type(s).__getitem__(s, slice(i, j)) . Example of implementation :

     class FakeSeq: ... def calc_item(self, i): ... def __getitem__(self, item): if isinstance(item, slice): indices = item.indices(len(self)) return FakeSeq([self.calc_item(i) for i in range(*indices)]) else: return self.calc_item(i) 

    slice.indices() method is used to help implement the necessary behavior for the slice. For example, "a"[-42:1000] :

     >>> slice(-42, 1000).indices(len("a")) (0, 1, 1) # start, stop, step >>> list(range(*_)) [0] # indices >>> 'a'[-42:1000] == 'a'[0] True 

    In fact, CPython calls a similar PySlice_GetIndicesEx() function for strings.

    In general, the types passed to slice() unlimited and their interpretation depends on the specific type:

     class Slicable(object): def __getitem__(self, given): if isinstance(given, slice): # do your handling for a slice object: print(given.start, given.stop, given.step) else: # Do your handling for a plain index print(given) s = Slicable() s[1] s[1:2] s[1:2:3] s[1:2:3,4] s[()::1j,] s[()::1j,None] 

    Result

     1 1 2 None 1 2 3 (slice(1, 2, 3), 4) (slice((), None, 1j),) (slice((), None, 1j), None) 

    Real example: tuples, ... and 1j indices are used in numpy .


    What does * (asterisk) and ** double asterisk mean in Python?

    I didn’t find the part about zeroing of negative indices where it was clearly documented (except for the above quote from the introductory guide (informally): "out [ slice. ] indices() handles omitted and out-of-the-bounds indices in a way consistent with regular slices
    The highlighted part translates as: “this innocuous phrase hides a bunch of confusing parts”