Dans cette vidéo, nous allons parler d'un ensemble de types qu'on appelle les séquences. Les séquences en Python regroupent notamment les listes, les tuples, les chaînes de caractères et les bytes. Nous verrons qu'elles regroupent également encore plus de types que cela. Ouvrons maintenant un interpréteur Python pour commencer à jouer avec les séquences.
Une séquence en Python est un ensemble fini et ordonné d'éléments, indicés de 0 à n - 1 si j'ai n éléments. Prenons un exemple de séquence et commençons avec une chaîne de caractères. Voici une chaîne de caractères. Sur les séquences, je vous rappelle que la chaîne de caractères est juste un exemple de séquence mais que les listes par exemple, ou les tuples, sont également des objets séquences. Regardons un exemple d'opération que je peux faire, commune à toutes les séquences.
Je peux déjà commencer par accéder à chaque élément de la séquence, avec la notation crochets. s[0] me permet d'accéder au premier élément de la séquence, puisque, je vous le rappelle, les séquences sont numérotées à partir de 0. s[9] va me permettre d'accéder au dernier élément de ma séquence puisqu'ici, ma séquence a 10 éléments. D'ailleurs, à ce propos, comment je fais pour connaître le nombre d'éléments dans une séquence ? J'utilise la fonction built-in len. Donc je fais un len(s) et ça va me retourner que j'ai effectivement dix éléments dans ma séquence.
Toutes les séquences supportent également le test d'appartenance, c'est une opération très puissante en Python puisque je peux faire : est-ce que 'egg' in s et ça va me retourner vrai, effectivement, la chaîne de caractères 'egg' est dans la chaîne de caractères 'egg, bacon'. De même, je peux faire 'egg' not in s, qui est le test de non appartenance, et qui va me retourner faux, puisque, effectivement, 'egg' est dans la chaîne de caractères donc le test : n'est-il pas dans la chaîne de caractères ? retourne faux. Donc ce test d'appartenance, vous remarquez qu'il est extrêmement expressif, puisque c'est quasiment du langage naturel. Je regarde est-ce que ma chaîne de caractères egg in s, est-ce que ma chaîne est dans s.
Ensuite, je peux faire de la concaténation de séquences. Regardez ma séquence s, je peux très bien lui rajouter la chaîne de caractères 'and beans'. Et cette concaténation va me produire une nouvelle chaîne de caractères puisque les opérations sur les séquences ne les modifient pas, puisque typiquement une chaîne de caractères n'est pas mutable, mais ça retourne un nouvel objet, dans ce cas-là, un nouvel objet de type chaîne de caractères.
J'ai également des opérations comme par exemple index(), qui me permet de trouver la première occurrence par exemple de la lettre g. Effectivement, la première occurrence de la lettre g, c'est à la place 1. Ou par exemple, count() qui me permet de compter le nombre d'éléments, le nombre de g que j'ai dans ma séquence. Donc ici, on voit que j'ai 2 fois la lettre g.
Je peux également appliquer les fonctions built-in min() et max(), qui me retournent le minimum et le maximum de ma séquence. Dans ce cas-là, comme c'est une chaîne de caractères, c'est en utilisant l'ordre lexicographique.
Et j'ai une dernière opération qui est l'opération de shallow copy qui me permet de faire… alors, je vais prendre une séquence plus simple, par exemple, un x, et je veux afficher 30 x à mon écran, je vais faire x fois 30 et ça va me faire une copie 30 fois de cette chaîne de caractères 'x'. Nous verrons dans la suite que cette opération produit en fait une shallow copy qui peut avoir des effets de bord lorsque la séquence multipliée n'est pas un immuable mais un objet de type mutable. Mais nous reviendrons sur ça dans la suite.
Nous allons maintenant regarder une dernière opération très importante sur les séquences qui s'appelle l'opération de slicing. Pour illustrer cette opération de slicing, qui est valable pour toutes les séquences donc pour les chaînes de caractères puisque c'est l'exemple que l'on va regarder mais également pour les listes, je vais créer une chaîne de caractères qui s'appelle 'egg, bacon' et donc ici, je vous représente la chaîne de caractères avec l'indice de chaque élément. On voit que e, c'est l'élément d'indice 0, g, l'élément d'indice 1, le deuxième g, l'élément d'indice 2, etc… Je vais maintenant faire une opération de slicing. L'opération de slicing se note de la manière suivante : on va mettre une borne de gauche, deux points, une borne de droite. La borne de gauche, en vert, est incluse et la borne de droite est exclue. Donc ici, s[0:3] va me retourner tous les éléments qui vont entre 0 inclus et 3 exclu, donc c'est 2 ; ça va donc me retourner la chaîne de caractères 'egg'. Il est très important de comprendre que l'opération de slice retourne à chaque fois un nouvel objet. Prenons un deuxième exemple, s[5:10], ça va me retourner tous les éléments allant de 5 inclus à 10 exclu, 10 moins 1, ça fait 9, ça va donc me retourner la chaîne de caractères 'bacon'.Si je fais s[ :3], si vous ne spécifiez pas la borne de gauche, vous allez parcourir tous les éléments du début jusqu'au 3 exclu, ça va donc me parcourir tous les éléments allant de e jusqu'à 3 exclu, c'est 2, ça va vous retourner la chaîne de caractères 'egg'. Et si vous ne spécifiez pas la borne de droite, ça va vous retourner tous les éléments allant de 5 jusqu'à la fin, donc ça va vous retourner 'bacon'. Pour finir, si vous ne spécifiez ni la borne de gauche, ni la borne de droite, ça vous retourne la chaîne de caractères mais c'est important : cette opération de slice ne va pas vous retourner la chaîne de caractères elle-même, ça va vous retourner une copie de cette chaîne de caractères. En fait, nous verrons dans la suite qu'on appelle cette opération une opération de shallow copy.
Maintenant, prenons un autre exemple. On va rajouter à notre slice la notion de pas. Dans un slice, on peut donner une borne de droite, une borne de gauche et également un pas, c'est-à-dire, on va parcourir les éléments un sur deux si on donne un pas de deux. Regardons cet exemple : s, de 0 à 10 par pas de 2, ça veut dire qu'on va parcourir les éléments allant de 0 à 10 exclu par pas de 2. Donc e, g, l'espace, a, o. Ça me retourne donc la chaîne de caractères 'eg ao'. Maintenant, prenons s[ : :2]. Ça me parcourt tous les éléments allant du début à la fin par pas de 2. Ça va me retourner 'eg ao' de nouveau. Si maintenant je fais s[ : 8 : 3], ça parcourt tous les éléments du début jusqu'à 8 exclu par pas de 3. Ça va donc me retourner 'e,a'. Et si je fais s[2 : : 3], ça me parcourt tous les éléments de 2 jusqu'à la fin par pas de 3, 'gbo'.
Regardons maintenant cet exemple. Qu'est-ce qu'il se passe si je fais s[100] ? s[100], c'est un indice qui est en dehors de ma chaîne de caractères, je vais donc avoir une erreur qu'on appelle une exception. Mon exception, comme toujours en Python, est très explicite ; elle s'appelle IndexError et elle m'écrit le message d'erreur : string index out of range, ça veut dire que l'indice de ma chaîne de caractères est en dehors des indices couverts par cette chaîne. Par contre, si maintenant, je fais s[5:100], je vais obtenir tous les éléments qui vont de 5 jusqu'à la fin de la chaîne de caractères. Pourquoi est-ce que dans ce cas-là je n'ai pas d'erreur ? Parce qu'en fait, le slice est un objet et Python va faire l'opération suivante : il va prendre tous les indices couverts par le slice, donc les indices allant de 5 à 100, et il va chercher l'intersection avec les indices disponibles dans notre objet chaîne de caractères. Et il va retourner uniquement les éléments qui sont à l'intersection. Ici on voit que l'intersection est non nulle, c'est 'bacon', il me retourne 'bacon'. Si je fais un slice de 100 à 200, dans ce cas-là, les indices représentés par le slice et les indices représentés par ma chaîne de caractères n'ont pas d'intersection, donc mon slice va me retourner un objet, toujours de type chaîne de caractères mais qui est vide.
Pour finir avec les chaînes de caractères, nous allons parler des indices négatifs. Regardons cet exemple-là. Les indices négatifs, c'est comme les indices positifs sauf qu'ils sont numérotés à partir de la fin. C'est donc un moyen très commode d'accéder aux derniers éléments d'une séquence lorsqu'on sait leur position à la fin de la séquence. Donc s[-10:-7] va me retourner tous les éléments allant de -10 inclus jusqu'à -7 exclu. Dans ce cas-là, on va aller de -10 à -8, ça me retourne 'egg'. Ce n'est pas parce que j'ai des indices négatifs que je parcours ma séquence dans un autre sens ; je parcours toujours ma séquence de la gauche vers la droite. Si je fais s[:-3], ça me retourne tous les éléments allant du début jusqu'à -3 exclu, c'est-à-dire -4, ça va me retourner 'egg, ba'. Et si maintenant je fais s[ : :-1], le pas étant négatif, cette fois, ça va parcourir ma séquence dans le sens inverse, de la droite vers la gauche. C'est donc une notation qui est très souvent utilisée pour renverser une séquence. Donc s[ : : -1] va me retourner ma séquence et l'afficher dans l'ordre inverse. Si maintenant, je fais s[2 : 0 : -1], ça va m'inverser ma séquence et prendre un sous-ensemble allant de droite à gauche, donc allant de 2 inclus jusqu'à 0 exclu, ce qui va me retourner la sous-chaîne 'gg'. Si je fais s[2 : : -1], ça me retourne ma séquence en allant de 2 jusqu'au début.
Dans cette vidéo, nous avons vu les principales caractéristiques des objets qui sont regroupés dans l'ensemble des séquences, sous le nom de séquences. On a vu le test d'appartenance: in, not in ; on a vu qu'on pouvait accéder aux éléments d'une séquence avec la notation crochets ; et surtout, nous avons vu la notion très importante de slice qu'il est important de maîtriser puisque vous aurez à manipuler de nombreuses séquences dans vos programmes Python.