Quelle est l'utilité de la fonction intégrée slice
et comment puis-je l'utiliser?
Je connais la manière directe de découper Pythonic - l1[start:stop:step]
. Je veux savoir si j'ai un objet tranche, comment puis-je l'utiliser?
Vous créez une tranche en appelant slice avec les mêmes champs que vous utiliseriez si vous effectuez la notation [start: end: step]:
sl = slice(0,4)
Pour utiliser la tranche, passez-la comme s'il s'agissait de l'index dans une liste ou une chaîne:
>>> s = "ABCDEFGHIJKL"
>>> sl = slice(0,4)
>>> print(s[sl])
'ABCD'
Disons que vous avez un fichier de champs de texte de longueur fixe. Vous pouvez définir une liste de tranches pour extraire facilement les valeurs de chaque "enregistrement" de ce fichier.
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('')
Tirages:
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
Les crochets suivant une séquence indiquent l'indexation ou le découpage en fonction de ce qui se trouve à l'intérieur des crochets:
>>> "Python rocks"[1] # index
'y'
>>> "Python rocks"[1:10:2] # slice
'yhnrc'
Ces deux cas sont traités par la méthode __getitem__()
de la séquence (ou __setitem__()
si à gauche d'un signe égal.) L'index ou la tranche est transmis aux méthodes comme un seul , et la façon dont Python fait cela est en convertissant la notation de tranche, (1:10:2
, dans ce cas) en un objet tranche: slice(1,10,2)
.
Donc, si vous définissez votre propre classe de type séquence ou remplacez les méthodes __getitem__
Ou __setitem__
Ou __delitem__
D'une autre classe, vous devez tester l'argument index pour déterminer s'il est un int
ou un slice
, et procédez en conséquence:
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")
Un objet slice
a trois attributs: start
, stop
et step
, et une méthode: indices
, qui prend un seul argument, la longueur de l'objet et renvoie un 3-Tuple: (start, stop, step)
.
>>> class sl:
... def __getitem__(self, *keys): print keys
...
>>> s = sl()
>>> s[1:3:5]
(slice(1, 3, 5),)
>>> s[1:2:3, 1, 4:5]
((slice(1, 2, 3), 1, slice(4, 5, None)),)
>>>
La fonction slice
renvoie slice objects . Les objets Slice sont l'un des types internes de Python, qui sont optimisés pour les performances de lecture - tous leurs attributs sont en lecture seule.
Modifier slice
pourrait être utile si vous souhaitez changer le comportement par défaut. Par exemple, lxml
utilise la notation par tranche pour accéder aux éléments DOM (cependant, je n'ai pas confirmé moi-même comment ils l'ont fait).
En essayant de répondre Sous-ensemble d'une chaîne basée sur une variable , je me suis rappelé que numpy a une manière syntaxiquement agréable de définir des objets de tranche:
>>> import numpy as np
>>> s = "The long-string instrument is a musical instrument in which the string is of such a length that the fundamental transverse wave is below what a person can hear as a tone."
>>> z = np.s_[18:26] # in this case same as slice(18, 26, None)
>>> s[z]
'strument'
Le problème résolu ici est de savoir comment stocker la tranche dans une variable pour une utilisation ultérieure, et np.s_
permet de faire exactement cela. Oui, ce n'est pas intégré, mais comme cette question d'origine a été redirigée ici, j'ai l'impression que ma réponse appartient ici également. En outre, numpy était l'une des raisons pour lesquelles des capacités de découpage aussi avancées ont été ajoutées à Python, IIRC.
Un exemple de "découpage" plus complexe:
>>> data = np.array(range(6)).reshape((2, 3))
>>> z = np.s_[:1, 1:2]
>>> data[z]
array([[1]])
>>> data
array([[0, 1, 2],
[3, 4, 5]])
>>> z
(slice(None, 1, None), slice(1, 2, None))
où z est maintenant un tuple de tranches.