The call built-in slice
Python is not really a function - like some other Python calls, it’s actually a class that creates the object slice
.
The chances of you needing to use slice
directly are quite small, but there are some uses - in general more for you to check whether an object is a slice
and use it, than to create one directly.
The Slice object is what is used internally by Python when using "slice notation" (Slice Notation) to delimit a subset of a sequence, such as a list or a string.
This notation is nothing more than using numbers separated by :
within a pair of brackets [ ]
used as an index - how do we:
In [70]: a = "banana"
In [71]: a[1:4]
Out[71]: 'ana'
Or
In [72]: b = list(range(10, 20))
In [73]: b
Out[73]: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
In [74]: b[:-5:2]
Out[74]: [10, 12, 14]
(in that case, the slice [:-5:2]
should be read as: take the sub-sequence from the beginning, up to 5 positions before the end, counting from 2 in 2).
As you probably know, all operations on Python objects are translated internally for calls to "magic" methods that have a predefined name - the best documentation for these methods is the 'data model" of the language, at this address: https://docs.python.org/3/reference/datamodel.html
In particular, when we get, do an assignment or delete (with the command del
) a sub-sequence within a sequence Python calls respectively the methods __getitem__
, __setitem__
and __delitem__
of the object class representing the sequence.
In this process, Python transforms the numbers placed in the slice notation between brackets into an object slice
. That is, Python itself calls the "function" slice
for us.
The object slice
in turn is quite simple, we can view the documentation or introspect it using the dir
:
In [75]: a = slice(1, 4)
In [76]: dir(a)
Out[76]:
[...
'indices',
'start',
'step',
'stop']
(i deleted the magical methods of Slice because they are not important) - if you look at "start", "step" and "stop", they correspond to the attributes we passed to the beginning and end of the sequence, and "None" to step
(step), which is the third optional argument)
The method indices
requires an integer to represent the size of the sequence - and all it does is, taking into account the length of the sequence passed as parameter, compute the start, end and step indices already taking into account the omitted parameters (i.e., left blank before or after the :
), negative indices, etc... The values returned by the call to the methodindice
can be used directly in the "function" range
to generate all the indexes of that slice.
It’s easier to visualize with an example: let’s create a subclass of list
that always returns all the elements of a slice transformed into strings:
class StringSliceList(list):
def __getitem__(self, indices):
if isinstance(indices, slice):
results = []
start, stop, step = indices.indices(len(self))
for i in range(start, stop, step):
results.append(str(super().__getitem__(i)))
else:
results = super().__getitem__(indices)
return results
Okay, with that we can play in the interactive terminal:
In [84]: a = StringSliceList(range(20))
In [85]: a[5:10]
Out[85]: ['5', '6', '7', '8', '9']
The object Slice can be passed directly between brackets, but it will always be less readable than using directly the notation with ":":
In [86]: a[slice(5,10)]
Out[86]: ['5', '6', '7', '8', '9']
I believe that your maintenance as a built-in by default Python is more of a slip-up than anything else - it’s a class that could very well be in the module types
. But as this was in the transition to Python 3, it is also something very little important to break compatibility, so it gets.
Trivia:
In the case of a multi-dimensional index, where several axes are separated by ,
inside the brackets, as used in Numpy matrices, each component separated by ,
can be converted to an object slice
separate.
class Test:
def __getitem__(self, indices):
print(indices)
Can be used:
In [89]: Test()[1:10, :, -1:5:10]
(slice(1, 10, None), slice(None, None, None), slice(-1, 5, 10))
And that doesn’t happen if you put an extra pair of () inside the [], because it creates a tuple that doesn’t have the components converted to objects of the type slice
:
In [90]: Test()[(1:10, :, -1:5:10)]
File "<ipython-input-90-32002bdbab86>", line 1
Test()[(1:10, :, -1:5:10)]
^
SyntaxError: invalid syntax
sorry for the downvote, but the question is about the built-in
slice
not on the Slice Notation .– jsbueno
Good, I got it.
– Vinicius Morais