Accueil

Tutoriel Python - sommaire

Vous pouvez me contacter via Facebook (questions, critiques constructives) : page Facebook relative à mon site

Approfondissements sur les structure itérables

Si vous avez lu tous les chapitres précédents (et pas simplement survolé), vous avez déjà appris beaucoup de choses. Mais vous avez peut-être le sentiment de tout mélanger. Il est possible que vous soyez effrayés par les connaissances à retenir.
Je m'en vais vous rassurer. D'abord il ne faut pas tout apprendre par coeur ; c'est impossible tant le langage Python est riche. Il suffit que vous disposiez des astuces pour retrouver rapidement l'information dont vous avez besoin.

Dans ce chapitre, je ne vais pas aborder de nouvelles notions mais simplement revenir mais en approfondissant, sur les structures itérables (objets des classes str, list, tuple, dict, set) découverts dans le chapitre 8.
N'hésitez pas auparavant à revenir sur ce chapitre. Chapitre 8

Commande dir()

Entre les listes, les tuples, les dictionnaires, les ensembles vous êtes perdus. Quel type de séquence utilisez ???
Quelles méthodes puis-je employer à un ensemble. Sont-elles les mêmes que celles relatives à un objet de la classe 'list' ou 'tuple' ou 'dict' ou 'str' ?
Pour connaitre les méthodes d'une classe il suffit de taper dans la console de Python : dir(nomClasse).

>>> dir(list)
... 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'
>>> dir(set)
... 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 
'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 
'union', 'update'
>>> dir(tuple)
... 'count', 'index'
>>> dir(dict)
… 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
>>>
>>> dir(str)
 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format',
 'format_map', 'index', 
 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 
 'isprintable', 'isspace', 
 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 
 'removesuffix', 'replace',
 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith',
 'strip', 'swapcase', 'title',
 'translate', 'upper', 'zfill'
>>>

Ci-dessous j'ai supprimé des captures d'écran les méthodes spéciales dont nous n'avons pas à nous préoccuper pour l'instant.
Notez le nombre impressionnant de méthodes que l'on peut appliquer à une chaine (instance de la classe 'str'). Par contre les méthodes de la classe "tuple" ne sont qu'au nombre de 2 ...
Notez que certaines méthodes sont aussi communes à plusieurs classes. Ainsi on retrouve la méthode clear() pour les listes, les ensembles, les dictionnaires.
également la méthode index() : classes "list", "tuple", "str".
Par contre l'ajout d'un élément se fait avec add() pour un ensemble mais avec append() pour une liste ...

Par contre nulle trace des fonctions dir(), print(), input(), type(), range(), etc.
Il s'agit de fonctions natives (ou génériques ou standards) : elles peuvent s'appliquer à des objets appartenant à des classes différentes.

Fonctions génériques et méthodes de classes

Il ne faut pas confondre sort() et sorted() de même que reverse() et reversed().
sort() & reverse() sont de méthodes de la classe 'list' tandis que sorted() & reversed() sont des fonctions génériques qui peuvent s'appliquer à n'importe quelle séquence itérable (liste, tuple, dictionnaire, ensemble ou chaine).

>>> monset ={5,3,1,9,11,7}
>>> monset.reverse()
AttributeError: 'set' object has no attribute 'reverse'
>>> monset.sort()
AttributeError: 'set' object has no attribute 'sort'
>>> sorted(monset)
[1, 3, 5, 7, 9, 11]
>>> machaine ="xzyuaoipqsbdfqcd"
>>> sorted(machaine)
['a', 'b', 'c', 'd', 'd', 'f', 'i', 'o', 'p', 'q', 'q', 's', 'u', 'x', 'y', 'z']
>>> sorted(machaine, reverse =True)
['z', 'y', 'x', 'u', 's', 'q', 'q', 'p', 'o', 'i', 'f', 'd', 'd', 'c', 'b', 'a']
>>> maliste=[5,3,7,11,13,7,3]
>>> sorted(maliste,reverse =True)
[13, 11, 7, 7, 5, 3, 3]
>>> max(maliste)
13
>>> max(machaine)
'z'
>>> max(monset)
11

Rappel : La syntaxe n'est pas la même selon que vous faites appel à une méthode de classe et une fonction native.
objet.méthode()
fonction(objet)

Retour sur les chaines ou "strings"

L'image est grivoise mais le discours qui suit est des plus sérieux.

Je rappelle que dans le chapitre 8, nous avons vu qu'il était facile de produire une chaine à partir d'une liste (ou d'un tuple ou d'un dictionnaire ou d'un ensemble) via la méthode join(). Il est en effet, souvent plus simple de manipuler une chaine qu'une suite de données.

Quelques méthodes applicables aux chaines

Jusqu'à présent je n'ai présenté que quelques méthodes de la classe 'str' alors qu'elles sont très très nombreuses ...
Commençons :

>>> chaine1 ="bonjour"
>>> chaine2 ="123456"
>>> chaine3 ="bonsoir chère madame"
>>> chaine3.capitalize()
'Bonsoir chère madame'
>>> chaine3.upper()
'BONSOIR CHÈRE MADAME'
>>> chaine3.lower()
'bonsoir chère madame'
>>>
>>> chaine2 ="123456"
>>> chaine2.upper()
'123456'

Les méthodes lower(), upper(), capitalize() "modifient la casse".
Bien évidemment ces méthodes n'ont aucun impact sur des chaines composées de chiffres.

Davantage de méthodes

Petit à petit on découvre la richesse des méthodes applicables à une chaine.

>>> monTel ="0601010101" >>> type(monTel) <class 'str'> >>> monTel.isnumeric() True >>> monTel.isdigit() True >>> nbrepi ="3.14" >>> nbrepi.isnumeric() False >>> nbrepi.isdigit() False >>> >>> monTel.count("1") 4 >>> maliste =list(monTel) >>> maliste ['0', '6', '0', '1', '0', '1', '0', '1', '0', '1'] >>> montuple = tuple(monTel) >>> montuple ('0', '6', '0', '1', '0', '1', '0', '1', '0', '1') >>> monset = set(monTel) >>> monset {'1', '0', '6'} >>> for i in monTel: ... print(i) ... 0 6 0 ... 0 1 >>>

Rechercher une sous-chaine dans une chaine

Pour réchercher un caractère (ou plusieurs) dans une chaine, vous pensez à index() mais il existe aussi find(), rindex() et rfind().

>>> machaine ="avec cesar"
>>> machaine.index('a')
0
>>> machaine.index('y')
>>> machaine.find('y')
-1
>>> machaine.rindex('a')
8
>>> machaine.rfind('a')
8
>>> machaine.rindex('y')
ValueError: substring not found
>>> machaine.rfind('y')
-1
>>> "y" in machaine
False
>>> "a" in machaine
True
>>> machaine_cryptee = machaine.replace('a','1').replace('e','2')
>>> machaine_cryptee
'1v2 c2s1r'

Effacer les espaces dans une chaine

Exemple :

>>> machaine = "     bon jour    "
>>> machaine.strip()
'bon jour'
>>> machaine.lstrip()
'bon jour    '
>>> machaine.rstrip()
'     bon jour'
>>> machaine.strip().replace(" ","")
'bonjour'

lstrip() efface les espaces en début de chaine, rstrip() efface les espaces en fin de chaine ; strip() équivaut à lstrip().rstrip().
Pour effacer les espaces en milieu de chaine il faut utiliser replace(" " ."").

Extraire une sous-chaine d'une chaine

Obtenir une chaine débarassée de symboles et espaces

Les méthodes strip(), lstrip() & lstrip() sans arguments effacent les espaces. Mais vous pouvez argumenter ces méthodes.

Exemple : on souhaite débarasser une chaine des espaces, * -

>>> machaine =" *  Bonjour * - "
>>> machaine = machaine.lstrip(" *-").rstrip(" * -")
>>> machaine
'Bonjour'
>>>

Pour effacer des caractères parasites en milieu de de chaine il faut utiliser replace().
Exemple ci-dessous.

>>> chainebizarre ="B*- on*-jour"
>>> chainecorrige = chainebizarre.replace(" ","").replace("*","").replace("-","")
>>> chainecorrige
'Bonjour'

On remplace les espaces, * et - par du vide.

Le "slicing" ou tranchage

Le 'slicing" a déjà été évoquée au chapitre 2. Une simple expression entre crochets dit beaucoup de choses. Aussi la compréhension de cette expression n'est pas toujours facile. Sachez que l'indice peut être une valeur négative afin d'extraire à partir de la fin (ou droite de la chaine).

Donc le cadre du "slicing", l'indice peut avoir une valeur négative ; ce qui veut dire : extraire à partir de la fin (ou de la droite).

Exemple : dans des chaines on trouve le mon d'une espèce précédé ou suivi d'un code indiquant le groupe : "bi" comme bivalve ; "ga" comme gastéropode.
On veut afficher seulement le nom de l'espèce ; il faut donc pratiquer le "slicing" pour se débarasser du code-groupe.

>>> espece ="bi-moule commune"		# si code en début de chaine
>>> print(espece[3:])
moule commune
>>> espece2 ="bulot-ga"				#si code en fin de chaine
>>> print(espece2[:-3])
bulot

On affiche uniquementn le nom de l'espèce.

Autre exemple de tranchage :
Rappelez vous, dans le chapitre 6 j'ai évoqué le code de César : un système de cryptage simple reposant sur un décalage de n lettres.

>>> alphabet ="abcdefghijklmnopqrstuvwxyz"
>>> n=2
>>> alphabet_2n =alphabet[n:] + alphabet[:n]
>>> alphabet_2n
'cdefghijklmnopqrstuvwxyzab'

Grâce au "slicing" j'obtiens la table de conversion ("a" devient "c" , "b" devient "d" ... "z" devient "b") dans l'hypothèse d'un décalage de 2 (valeur de n).
Notez que - et c'est important en programmation - l'expression entre crochets peut contenir des variables.

Convertir les chaines en nombres

Voilà une problèmatique que vous allez rencontrer souvent en programmation Python.
En effet la fonction input() retourne toujours une chaine même si vous avez saisi que des chiffres.

Tapez les commandes suivantes dans la console Python :

>>> chaine ="1245" >>> int(chaine) 1245 >>> chaine2 ="1245.55" >>> int(chaine2) ValueError: invalid literal for int() with base 10: '1245.55' >>> nombre =eval(chaine2) >>> type(nombre) <class 'float'> >>> nombre 1245.55

La fonction native int(chaine) convertit une chaine en entier si celle-ci ne contient qu'une suite de chiffres mais "plante" si le format de la chaine est celle d'un flottant.
La fonction native eval(chaine) peut convertir une chaine en flottant.

Transformer une chaine en liste

Employer la fonction 'list' n'est pas forcément la bonne solution comme je le montre ci-dessous.

>>> chaine ="un deux trois quatre cinq" >>> liste =list(chaine) >>> liste ['u', 'n', ' ', 'd', 'e', 'u', 'x', ' ', 't', 'r', 'o', 'i', 's', ' ', 'q', 'u', 'a', 't', 'r', 'e', ' ', 'c', 'i', 'n', 'q'] >>> liste = chaine.split() >>> liste ['un', 'deux', 'trois', 'quatre', 'cinq'] >>> type(liste) <class 'list'>

Par contre la méthode slipt() produit une liste où chaque mot de la chaine d'origine devient un élément.

Justement, je vais maintenant revenir sur les listes.

Retour sur les listes

Rappels de méthodes applicables à un objet 'list'

>>> maliste =[2,3,2,5,7,9] >>> type(maliste) <class 'list'> >>> maliste.append(11) >>> maliste [2, 3, 2, 5, 7, 9, 11] >>> maliste.reverse() >>> maliste [11, 9, 7, 5, 2, 3, 2] >>> maliste.sort() >>> maliste [2, 2, 3, 5, 7, 9, 11] >>> maliste.count(2) 2 >>> for i in maliste: ... print(i) ... 2 3 2 5 7 9 11 >>> maliste.remove(11) >>> maliste.pop(0) >>> maliste [2, 3, 5, 7, 9] >>> maliste.clear() >>> maliste []

Il s'agit ici d'une piqure de rappel. Toutes ces méthodes ont déjà été évoquées dans des chapitres précédents.
Je signale qu'il existe aussi les méthodes extend() pour ajout n éléments en fin de liste et insert(position, valeur) pour insérer un élément.

Produire tuple, ensemble à partir d'une liste

Il s'agit aussi de rappels.

>>> maliste =[5,2,3,2,4,7,9,7] >>> montuple = tuple(maliste) >>> montuple (5, 2, 3, 2, 4, 7, 9, 7) >>> type(montuple) <class 'tuple'> >>> monset =set(maliste) >>> monset {2, 3, 4, 5, 7, 9} >>> type(monset) <class 'set'>

Pour créer un objet 'tuple' à partir d'une liste il faut utiliser la fonction tuple()
Pour produire une objet 'set' à partir d'une liste il faut utiliser la fonction set()
Notez que la fonction set() est "intelligente" : produit le 'set' sans doublons.

Retour sur les ensembles

>>> monset ={5,3,2,1,4,7,6} >>> type(monset) <class 'set'> >>> sorted(monset) [1, 2, 3, 4, 5, 6, 7] >>> reversed(monset) TypeError: 'set' object is not reversible >>> for i in monset: ... print(i) ... 1 2 3 4 5 6 7 >>> monset.add(9) >>> monset.add(9) >>> monset {1, 2, 3, 4, 5, 6, 7, 9} >>> monset.discard(6) >>> monset {1, 2, 3, 4, 5, 7, 9}

Un ensemble est une séquence "triable" mais pas réversible.
Un ensemble est une séquence itérable : peut être parcourue par un for.
Si vous tentez d'ajouter dans une séquence un élément qui existe déjà, il y a échec mais sans message d'erreur. Attention la méthode n'est pas "append" mais "add".
La méthode remove() peut s'appliquer à un ensemble mais il faut lui préférer la méthode discard() (pas de message éventuel d'erreur).
Il y a aussi les opérations sur les ensembles : union et intersection qui ont déjà été abordées dans le chapitre 8. Je vous renvoie à ce chapitre : chapitre 8

Retour sur les dictionnaires

Je rappelle qu'un dictionnaire est une structure qui comprend non pas des éléments mais des items.
Chaque item est composé d'une clé et d'une valeur avec ":" entre les deux (on parle aussi de "paire").

>>> repertoire = {"marius":"0601010101", "émile":"0602020202","bernard": "0603030303","damien":"0604040404"} >>> type(repertoire) <class 'dict'> >>> repertoire.get("damien") '0604040404' >>> repertoire.get("louise") >>> repertoire["françois"] ="0605050505" >>> rperteoire.pop("marius") '0601010101' >>> repertoire["émile"] = "0701010101" >>> repertoire.popitem() ('françois', '0605050505') >>> repertoire.clear() >>> repertoire {} >>> ajout = {'alain': '0601010101', 'bernard':'0602020202'} >>> type(ajout) <class 'dict'> >>> repertoire.update(ajout) >>> repertoire {'alain': '0601010101', 'bernard': '0602020202'} >>> repertoire_copie = repertoire >>> repertoire_copie {'alain': '0601010101', 'bernard': '0602020202'} >>> for item in repertoire.items(): ... print(item) ... ('marius', '0601010101') ('émile', '0602020202') ('bernard', '0603030303') ('damien', '0604040404') >>> for cle in repertoire.keys(): ... print(cle) ... marius émile bernard damien

Un dictionnaire est une structure itérable.
Mais la syntaxe de l'itération est un peu plus complexe que pour les autres types de données itérables.
Selon que vous voulez afficher les items (clé-valeur) OU seulement les clés OU seulement les valeurs il faut écrire : nomDico.items() / nomDico.keys() / nomDico.values.