Connaissez vous l’objet slice en Python ? 11


Python, le langage sans fond. Arriverai-je à n’avoir plus jamais d’article à écrire un jour ?

Tenez, hier, j’étais en train de lire un blog sur le Web, le bourrelet paresseusement calé entre mon dossier et la table, quand soudain, boum !

Je tombe sur ça :

>>> slice
<type 'slice'>

Aucun import. Rien.

Attend, il y a un type built-in slice en Python ? What the actual fucking fuck ?

Alors je testouille un truc, y croyant vaguement :

>>> lst = ['a', 'b', 'c', 'd']
>>> lst[1:3]
[u'b', u'c']
>>> lst[slice(1,3)]
[u'b', u'c']

Donc plutôt que de se trimbaler avec des tuples de valeurs dont il faudra tester ou imposer la taille. Plutôt que d’attendre en paramètre uniquement des entiers positionnels ou forcer le passage de None, on peut aussi tout simplement passer un slice à vos fonctions qui font du slicing.

Ça veut dire des objets slices en valeurs par défaut.

Ça veut dire des objets slices dans les mapping, les iterables, etc.

Un seul regret :

>>> from itertools import islice
>>> islice(lst, slice)
Traceback (most recent call last):
  File "<ipython-input-5-7eb2c7533070>", line 1, in <module>
    islice(lst, slice(1,3))
ValueError: Stop argument for islice() must be None or an integer: 0 <= x <= maxint.

Et ça c’est vraiment con.

11 thoughts on “Connaissez vous l’objet slice en Python ?

  • CriCri

    Bonjour,

    ben moi y en pas tout comprendre

    MacBook-Pro-de-Christophe:~ chris$ python
    Python 2.7.2 (default, Oct 11 2012, 20:14:37)
    [GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
    Type “help”, “copyright”, “credits” or “license” for more information.
    >>> lst = [‘a’,’b’,’c’,’d’]
    >>> lst[1:3]
    [‘b’, ‘c’]
    >>> lst[slice(1,3)]
    [‘b’, ‘c’]
    >>>

    Mais c’est pas grave (je lis avec attention avec l’espoir que peut-être un jour je pourrai entrevoir une petite éclaircie dans cette purée de pois) et merci tout de même pour cet article (et aussi pour tous les autres)
    Bonne journée et pourvu que ça continue
    Christophe
    slice c’est cool

  • kontre

    @CriCri: C’est quoi que tu ne comprends pas ? Si c’est les u, c’est à cause de from __future__ import unicode_literals que Sam utilise systématiquement (avec raison).

    Sinon les slices c’est cool, c’est d’ailleurs l’objet qu’on reçoit quand on crée une classe avec __getitem__ et qu’on passe… un slice. Hélas, ça ne marche pas avec n’importe quelle fonction :

    def test(x): print x
    test(1:2)
    File "<ipython-input-2-8dda64371f87>", line 1
        test(1:2)
              ^
    SyntaxError: invalid syntax

    Au passage, on peut faire de l’indexation à plusieurs dimensions avec __getitem__, on reçoit alors un tuple de slices:

    class Test(object):
        def __getitem__(self, index):
            print index
    t = Test()
    t[0:1]  # slice(0, 1, None)
    t[0:1, 5:6]  # (slice(0, 1, None), slice(5, 6, None))

    Les 3 propriétés de slice sont début, fin et pas, comme la notation avec les “:”. Plus d’infos dans la doc : http://docs.python.org/2/library/functions.html#slice

    @Sam
    Pour ton regret tu passes la classe slice à islice, au lieu d’une instance. Mais ça ne passe pas non plus avec une instance, cela dit. Par contre on peut récupérer les valeurs en utilisant les propriétés pour utilser un slice dans islice, mais c’est lourd :

    s = slice(2, 4)
    islice(lst, s.start, s.stop, s.step)  # <itertools.islice at 0x3c913c0>
  • Feadurn

    Un peu cryptique tout ca. Mais je comprends bien que tout les articles ne doivent/peuvent pas etre compris par des debutants/amateurs comme moi ;)

  • Batisteo

    Je ne sais pas si ça aide, ni si c’est juste, mais je pense que ce qu’il voulait montrer c’est que lst[1,3] est raccourci (très utilisé et bien pratique) de lst[slice(1,3)].
    Le fait de savoir ça permet d’avoir plus de choix pour la manipulation des liste, par exemple dans des fonctions :

        def sous_liste(lst, mon_slice=slice(1,3)):
            return lst[mon_slice]
     
        une_liste = [0, 2, 4, 6, 8, 10, 12]
        print sous_liste(une_liste))  # [2, 4]
        print sous_liste(une_liste, slice(4,8))  # [8, 10, 12]

    Il est terriblement bidon cet exemple, mais c’est pour illustrer la possibilité de slicer par défaut. J’espère que ça a pu aider…

    Par contre je ne connais pas islice, et n’ai donc pas compris le regret.

  • tarzan

    @kontre:

    >>> x=slice(1,5)
    >>> def p(x):
    ... print(x)
    ...
    >>> p(5)
    5
    >>> p(x)
    slice(1, 5, None)

    Sinon je comprends pas le problèmes avec islice.

  • kontre

    @tarzan: oui, on peut passer l’objet slice, mais on ne peut pas utiliser la notation avec les ‘:‘, plus claire et plus concise. p(1:5) est plus intuitif que p(slice(1,5)). Cette notation n’est acceptée qu’avec __getitem__ et pas de manière générale.

    On pourrait utiliser un decorateur qui crée une classe avec __getitem__ appelant la fonction et permettant d’appeler la fonction avec les crochets… Mmmh…

  • Sam Post author

    @CriCri : l’objet slice représente la notation [:], mais elle est stockable, passable en paramètre, et générable programmatiquement. Avant l’alternative c’était de se balader avec 3 valeurs, et si on utilisait pas 3, de mettre les autres à None.

    Par exemple, on peut faire :

    slices = [slice(1,3), slice(3), slice(4, -2, -1)]
    for s in slices:
        print lst[slices]

    Avant il fallait faire :

    slices = [(1, 3, None), (None, 3, None), (4, -2, -1)]
    for s in slices:
        print lst[s[0]:s[1]:s[2]]

    Ce qui est plus chiant à taper, mais surtout moins explicite. En prime les slices peuvet être inspectées de manière naturelle :

    >>> s.stop
    -1

    C’est surtout du sucre syntaxique, mais c’est mignon.

    @kontre: wow, je savais pas que tu pouvais passer plusieurs slices ! Bon j’ai corrigé ma typo sur le passage de slice au lieu de slice()

    @Feadurn : oui, on fait un petit mélange. Sinon y a toujours une partie qui finit par s’ennuyer.

    @Batisteo: +1.

    @Batisteo et @tarzan : islice, c’est une fonction qui permet de faire des slices sur des générateurs. La notation [] ne fonctionne pas sur les générateurs. Donc si slice() ne marche pas avec islice, ça veut dire qu’on ne peut pas l’utiliser sur les fichiers, les flux réseaux, les générateurs de liste, etc.

    @playest: obtenir un itérateur ne change pas le fait que la notation [] ne fonctionne pas sur les générateurs.

  • kontre

    À propos d’indexation, je viens de voir un truc sympa avec les dictionnaires, on peut aussi indexer avec plusieurs dimensions (mais bien sûr, les slices ne fonctionnent pas pour l’indexation), ça revient à passer un tuple :

    d = {}
    d[0, 0] = 1
    d[(0, 0)]  # 1

    (C’est dans les commentaires de cette page, qui parle de modéliser un plateau de jeu)

    Et sinon, un slice ne peut pas être une clé de dictionnaire, c’est pas hashable :

    hash(slice(1, 2))
    #Traceback (most recent call last)
    #  ...
    #TypeError: unhashable type
  • Sam Post author

    @Gawtarnik : malheureusement non, on ne prend pas de job à travers le blog, afin de garder notre anonymat. Cela aurait été avec plaisir sinon, ça faisait longtemps que je n’avais pas fait un petit séjour à Créteil :-)

Leave a comment

Your email address will not be published. Required fields are marked *

Utilisez <pre lang='python'>VOTRE CODE</pre> pour insérer un block de code coloré

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.