Algo. et prog. 2 en
Logo de Python
Arnaud COUTURIER - Python 3.10

Les séquences

Une séquence est un type de données qui représente une suite ordonnée et finie de N éléments indicés de 0 à N-1, et qui supporte certaines opérations qui sont détaillées dans cette page. Il existe plusieurs types built-in qui sont des séquences, comme par exemple:

On peut aussi créer des nouveaux types séquences personnalisés si on souhaite.

Indexation

Un élément d'une séquence peut être obtenu avec les crochets, on appelle ce mécanisme l'indexation, le premier élément étant à l'indice zéro, et le dernier à l'indice N-1 si la séquence est de longueur N:


		>>> L = [10, 20, 30]
		>>> L[0]
		10
		>>> L[1]
		20
		>>> L[2]
		30
		>>> range(10)[5]
		5
	

Essayer d'obtenir un élément au-delà du dernier indice, c'est-à-dire à partir de N inclus et au-delà, provoquera une erreur de type IndexError:


		>>> L = [10, 20, 30]
		>>> L[3]
		IndexError
		>>> L[4]
		IndexError
	

Les indices négatifs sont supportés car les séquences sont doublement indexées. Une première fois positivement en partant du début de la séquence à 0 jusqu'à la fin de la séquence à N-1. Et une seconde fois négativement du début de la séquence à -N jusqu'à la fin de la séquence à -1. Exemple pour la str "bonjour" (mais cela vaut pour tous les types séquences):

" B o n j o u r "
Indices positifs 0 1 2 3 4 5 6
Indices négatifs -7 -6 -5 -4 -3 -2 -1

		>>> "Bonjour"[0]
		'B'
		>>> "Bonjour"[-1]
		'r'
		>>> "Bonjour"[-2]
		'u'
		>>> "Bonjour"[-7]
		'B
		>>> "Bonjour"[-8]
		IndexError
	

On peut voir ↑ que les valeurs négatives plus petites que -N provoquent des IndexError.

Slices

Les slices sont une version plus sophitiquée de l'indexation, car elle permettent non pas d'obtenir un objet à un indice de la séquence, mais une portion de la séquence entre deux indices.

La version la plus simple des slices prend deux indices, séparés par le caractère deux-points. Le premier indice est celui de début inclus, le second est celui de fin exclu:


		>>> S = "Bonjour"
		>>> S[0:3]
		'Bon'
		>>> S[3:6]
		'jou'
	

Quand un slice a des indices qui n'ont pas de sens, comme par exemple le premier est plus grand que le second, ou bien des indices qui sortent des limites de la séquence, cela ne provoque pas d'erreur mais retourne une séquence vide (du même type):


		>>> S = "Bonjour"
		>>> S[3:3]
		''
		>>> S[6:3]
		''
		>>> S[100:200]
		''
	

Si les indices couvrent une portion de la séquence mais dépassent aussi les limites, alors le slice retourne uniquement cette portion de la séquence:


		>>> S = "Bonjour"
		>>> S[5:200]
		'ur'
	

On peut ne pas mettre le premier indice, dans ce cas ça signifie qu'on souhaite que la séquence résultat commence au début. Ça signifie zéro, mais pas forcément, comme on va le voir ensuite. On peut aussi ne pas mettre le second indice, dans ce cas ça signifie qu'on souhaite que la séquence résultat se termine à la fin de la séquence. Ça signifie N si la séquence est de longueur N, mais pas forcément, comme on va aussi le voir ensuite. Si on ne spécifie ni le premier ni le second indice, on obtient une nouvelle séquence identique à l'originale.


		>>> L = [10, 20, 30, 40, 50]
		>>> L[:3]
		[10, 20, 30]
		>>> L[3:]
		[40, 50]
		>>> L2 = L[:]
		>>> L2
		[10, 20, 30, 40, 50]
		>>> L2 is L1
		False
	

Attention: quand on fait une copie d'une liste avec le slice [:], il s'agit d'une copie superficielle, c'est à dire les références dans la nouvelle liste pointent toutes vers les mêmes objets que ceux pointés par les références dans la liste originale, les objets pointés ne sont pas dupliqués. On appelle cela une copie superficielle ou en anglais shallow copy, en opposition à copie profonde, ou deep copy où tous les objets sont dupliqués de façon récursive. Pour plus de détails voir la partie du cours sur le modèle de données de Python.

On peut rajouter un troisième nombre entier qui servira de pas. Si on ne le précise pas, il est de 1 par défaut. Il peut être une autre valeur, y compris une valeur négative, dans ce cas l'indice de début doit être plus grand que celui de fin:


		>>> S = "Bonjour"
		>>> S[0:5:2]
		'Bno'
		>>> S[0:5:3]
		'Bj'
		>>> S[5:0:-1]
		'uojno'
		>>> S[5::-1]
		'uojnoB'
		>>> S[::-1]
		'ruojnoB'
	

Notez que quand on compte en négatif ↑ l'indice de début 5 est toujours inclus et celui de fin 0 est exclu. La séquence résultat s'arrête à l'indice 1 quand on précise le dernier indice étant 0, alors que si on ne précise pas l'indice de fin cette fois-ci 0 est inclus.

Les slices peuvent utiliser les indices négatifs. Le fonctionnement reste le même, cependant quand on ne met pas l'indice de début le slice le remplace par -N contrairement à 0 pour les indices positifs. Quand on ne met pas l'indice de fin le slice le remplace par 0 contrairement à N pour les indices positifs.:


		>>> S = "Bonjour"
		>>> S[-4:-1]
		'jou'
		>>> S[-4:]
		'jour'
		>>> S[-4:0]
		''
		>>> S[:-1]
		'Bonjou'
		>>> S[-7:-1]
		'Bonjou'
	

(Étrangement S[-4:0] ne donne pas la même chose que S[-4:], pourtant ça devrait. Je ne sais pas expliquer ce comportement, si quelqu'un a la réponse j'aimerais la connaître.)

Enfin, on peut utiliser des indices négatifs avec des pas négatifs:


		>>> S = "Bonjour"
		>>> S[-2:-5:-1]
		'uoj'
		>>> S[:-5:-1]
		'ruoj'
		>>> S[-2::-1]
		'uojnoB'
	

len()

On peut obtenir la longueur d'une séquence avec la fonction built-in len(), diminutif du mot anglais length qui veut dire longueur.


		>>> len("Bonjour")
		7
		>>> len([True, 5.1, 30])
		3
		>>> len((True, 5.1, 30))
		3
		>>> len(range(10))
		10
	

Test d'appartenance avec in

Pour savoir si la séquence contient un objet ayant une certaine valeur on utilise l'opérateur in:


		>>> 'B' in 'Bonjour'
		True
		>>> 'b' in 'Bonjour'
		False
		>>> 20 in [10, 20, 30]
		True
		>>> 5 in range(10)
		True
		>>> 10 in range(10)
		False
	

Remarquez que pour les str on peut tester si une sous-chaîne est présente dans une chaîne:


		>>> 'Bon' in 'Bonjour'
		True
		>>> 'jour' in 'Bonjour'
		True
		>>> 'soir' in 'Bonjour'
		False
	

Suppression d'élément avec del

On peut supprimer des indices, pour les séquences mutables uniquement (par exemples les list, mais pas les str ou les tuples):


		>>> L = [10, 20, 30]
		>>> del L[1]
		>>> L
		[10, 30]
	

Concaténation avec +

Permet de mettre bout-à-bout plusieurs séquences. Le résultat est aussi une séquence de même type:


		>>> "Bonjour " + "à tous"
		'Bonjour à tous'

		>>> (10, 20) + (100, 200)
		(10, 20, 100, 200)
	

La séquence résultat est un tout nouvel objet, indépendant de ceux utilisés pour faire la concaténation:


		>>> L1 = [10, 20, 30]
		>>> L2 = [100, 200, 300]
		>>> L3 = L1 + L2
		>>> L3
		[10, 20, 30, 100, 200, 300]
		>>> L1
		[10, 20, 30]
		>>> L2
		[100, 200, 300]
		>>> L3 is L1
		False
		>>> L3 is L2
		False
	

Pour les listes qui sont mutables, la méthode extend() fait la même chose que l'opérateur + entre listes, mais ne crée pas de nouvel objet, la méthode modifie la liste directement, ce qui est plus efficace en terme de mémoire et vitesse d'exécution:


		>>> L1 = [10, 20, 30]
		>>> L2 = [100, 200, 300]
		>>> L1.extend(L2)
		>>> L1
		[10, 20, 30, 100, 200, 300]
		>>> L2
		[100, 200, 300]
	

Le type range ne supporte pas cette opération.

Multiplication par un nombre avec *

Assez similaire à l'opérateur + cet opérateur permet de répéter une séquence autant de fois que nécessaire. La séquence résultat sera un nouvel objet indépendant de l'original:


		>>> L1 = [10, 20, 30]
		>>> L2 = L1 * 3
		>>> L2
		[10, 20, 30, 10, 20, 30, 10, 20, 30]

		>>> L2 is L1
		False
	

Le type range ne supporte pas cette opération.

Méthode index()

Elle prend n'importe quel objet en paramètre, et retourne l'indice du premier objet de la séquence dont la valeur est égale à celle de l'objet en paramètre. Si la séquence ne contient pas un tel objet de valeur égale, la méthode provoque une ValueError:


		>>> L = ["a", -5, True, -5]
		>>> L.index("a")
		0
		>>> L.index(-5)
		1
		>>> L.index(True)
		2
		>>> L.index("Coucou")
		ValueError
	

Méthode count()

Elle prend n'importe quel objet en paramètre, et retourne le nombre de fois qu'un objet de la séquence est de valeur égale à celle de l'objet en paramètre.:


		>>> L = ["a", -5, True, -5]
		>>> L.count("a")
		1
		>>> L.count(-5)
		2
		>>> L.count("Coucou")
		0
	

Support des fonctions min() et max()

Ces deux fonctions built-in permettent d'avoir l'objet d'une séquence dont la valeur est considérée la plus petite ou la plus grande parmi tous ceux dans la séquence.


		>>> L = [50, -10, 30]
		>>> min(L)
		-10
		>>> max(L)
		50
	

La notion de plus grand et plus petit varie d'un type à un autre, par exemple entre nombres c'est la comparaison numérique qui nous est familière, tandis qu'entre chaînes de caractères ce sont d'autres règles qui s'appliquent pour savoir laquelle est plus petite ou plus grande. En général ce sont les nombres qui nous intéressent. Quoi qu'il en soit, quand les valeurs peuvent être comparées entre elles, alors on peut savoir laquelle est la plus grande ou la plus petite. Par exemple pour une liste de str:


		>>> L = ["Salut", "Coucou", "Bonjour"]
		>>> min(L)
		'Bonjour'
		>>> max(L)
		'Salut'
	

Support de la fonction reversed()

Avec cette fonction on peut inverser une séquence qu'on passe en paramètre, la fonction nous renvoie un objet de type iterator qu'on verra plus loins dans ce cours. Cet objet n'est PAS une séquence, il ne supporte donc pas les opérations listées sur cette page. Cependant on peut le transformer facilement en list en le passant en paramètre à la fonction list() qui nous renvoie la liste contenant tous les objets de cet iterator inversé:


		>>> r = reversed("Bonjour")
		>>> r
		<reversed object at 0x000001D11D29BDC0>
		>>> r[0]
		TypeError: 'reversed' object is not subscriptable
		>>> list(r)
		['r', 'u', 'o', 'j', 'n', 'o', 'B']