Python slice how-to, I know the Python slice but how can I use built-in slice object for it?
You create a slice by calling slice with the same fields you would use if doing [start:end:step] notation:
sl = slice(0,4)
To use the slice, just pass it as if it were the index into a list or string:
>>> s = "ABCDEFGHIJKL"
>>> sl = slice(0,4)
>>> print(s[sl])
'ABCD'
Let's say you have a file of fixed-length text fields. You could define a list of slices to easily extract the values from each "record" in this file.
data = """\
0010GEORGE JETSON 12345 SPACESHIP ST HOUSTON TX
0020WILE E COYOTE 312 ACME BLVD TUCSON AZ
0030FRED FLINTSTONE 246 GRANITE LANE BEDROCK CA
0040JONNY QUEST 31416 SCIENCE AVE PALO ALTO CA""".splitlines()
fieldslices = [slice(*fielddef) for fielddef in [
(0,4), (4, 21), (21,42), (42,56), (56,58),
]]
fields = "id name address city state".split()
for rec in data:
for field,sl in zip(fields, fieldslices):
print("{} : {}".format(field, rec[sl]))
print('')
# or this same code using itemgetter, to make a function that
# extracts all slices from a string into a tuple of values
import operator
rec_reader = operator.itemgetter(*fieldslices)
for rec in data:
for field, field_value in zip(fields, rec_reader(rec)):
print("{} : {}".format(field, field_value))
print('')
Prints:
id : 0010
name : GEORGE JETSON
address : 12345 SPACESHIP ST
city : HOUSTON
state : TX
id : 0020
name : WILE E COYOTE
address : 312 ACME BLVD
city : TUCSON
state : AZ
id : 0030
name : FRED FLINTSTONE
address : 246 GRANITE LANE
city : BEDROCK
state : CA
id : 0040
name : JONNY QUEST
address : 31416 SCIENCE AVE
city : PALO ALTO
state : CA
Square brackets following a sequence denote either indexing or slicing depending on what's inside the brackets:
>>> "Python rocks"[1] # index
'y'
>>> "Python rocks"[1:10:2] # slice
'yhnrc'
Both of these cases are handled by the __getitem__()
method of the sequence (or __setitem__()
if on the left of an equals sign.) The index or slice is passed to the methods as a single argument, and the way Python does this is by converting the slice notation, (1:10:2
, in this case) to a slice object: slice(1,10,2)
.
So if you are defining your own sequence-like class or overriding the __getitem__
or __setitem__
or __delitem__
methods of another class, you need to test the index argument to determine if it is an int
or a slice
, and process accordingly:
def __getitem__(self, index):
if isinstance(index, int):
... # process index as an integer
elif isinstance(index, slice):
start, stop, step = index.indices(len(self)) # index is a slice
... # process slice
else:
raise TypeError("index must be int or slice")
A slice
object has three attributes: start
, stop
and step
, and one method: indices
, which takes a single argument, the length of the object, and returns a 3-tuple: (start, stop, step)
.