web-dev-qa-db-fra.com

Python slice how-to, je connais la Python slice mais comment puis-je utiliser un objet slice intégré pour cela?)

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?

63
necromancer

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
85
PaulMcG

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).

33
Don O'Donnell
>>> 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).

3
Tim McNamara

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.

1
Roman Susi