Une introduction à Python 3

Image non disponible


précédentsommairesuivant

4. Conteneurs standard

Image non disponible

Le chapitre 3.4Les types de données entiers a présenté les types de données simples, mais Python offre beaucoup plus : les conteneurs.

De façon générale, un conteneur est un objet composite destiné à contenir d'autres objets. Ce chapitre détaille les séquences, les tableaux associatifs, les ensembles et les fichiers textuels.

4-1. Séquences

Une séquence est un conteneur ordonné d'éléments indexés par des entiers indiquant leur position dans le conteneur.

Python dispose de trois types prédéfinis de séquences :

  • les chaînes (vues précédemment) ;
  • les listes ;
  • les tuples(11).

4-2. Listes

4-2-1. Définition, syntaxe et exemples

Une liste est une collection ordonnée et modifiable d'éléments éventuellement hétérogènes.

Éléments séparés par des virgules, et entourés de crochets.

Exemples simples de listes :

 
Sélectionnez
couleurs = ['trèfle', 'carreau', 'coeur', 'pique']
print(couleurs) # ['trèfle', 'carreau', 'coeur', 'pique']
couleurs[1] = 14
print(couleurs) # ['trèfle', 14, 'coeur', 'pique']
list1 = ['a', 'b']
list2 = [4, 2.718]
list3 = [list1, list2] # liste de listes
print(list3) # [['a', 'b'], [4, 2.718]]

4-2-2. Initialisations et tests d'appartenance

Utilisation de la répétition, de l'itérateur d'entiers range() et de l'opérateur d'appartenance (in) :

 
Sélectionnez
>>> truc = []
>>> machin = [0.0] * 3
>>> truc
[]
>>> machin
[0.0, 0.0, 0.0]
>>>
>>> liste_1 = list(range(4))
>>> liste_1
[0, 1, 2, 3]
>>> liste_2 = list(range(4, 8))
>>> liste_2
[4, 5, 6, 7]
>>> liste_3 = list(range(2, 9, 2))
>>> liste_3
[2, 4, 6, 8]
>>>
>>> 2 in liste_1, 8 in liste_2, 6 in liste_3
(True, False, True)

4-2-3. Méthodes

Quelques méthodes de modification des listes :

 
Sélectionnez
>>> nombres = [17, 38, 10, 25, 72]
>>> nombres.sort()
>>> nombres
[10, 17, 25, 38, 72]
>>> nombres.append(12)
>>> nombres.reverse()
>>> nombres
[12, 72, 38, 25, 17, 10]
>>> nombres.remove(38)
>>> nombres
[12, 72, 25, 17, 10]
>>> nombres.index(17)
3
>>> nombres[0] = 11
>>> nombres[1:3] = [14, 17, 2]
>>> nombres
[11, 14, 17, 2, 17, 10]
>>> nombres.pop()
10
>>> nombres
[11, 14, 17, 2, 17]
>>> nombres.count(17)
2
>>> nombres.extend([1, 2, 3])
>>> nombres
[11, 14, 17, 2, 17, 1, 2, 3]

4-2-4. Manipulation des tranches (ou sous-chaînes)

Si on veut supprimer, remplacer ou insérer plusieurs éléments d'une liste, il faut indiquer une tranche (cf. chapitre 2.7.7Extraction de sous-chaînes) dans le membre de gauche d'une affectation et fournir une liste dans le membre de droite.

 
Sélectionnez
>>> mots = ['jambon', 'sel', 'miel', 'confiture', 'beurre']
>>> mots[2:4] = [] # effacement par affectation d'une liste vide
>>> mots
['jambon', 'sel', 'beurre']
>>> mots[1:3] = ['salade']
>>> mots
['jambon', 'salade']
>>> mots[1:] = ['mayonnaise', 'poulet', 'tomate']
>>> mots
['jambon', 'mayonnaise', 'poulet', 'tomate']
>>> mots[2:2] = ['miel'] # insertion en 3e position
>>> mots
['jambon', 'mayonnaise', 'miel', 'poulet', 'tomate']

4-2-5. Séquences de séquences

Les séquences, comme du reste les autres conteneurs, peuvent être imbriquées.

Par exemple :

 
Sélectionnez
>>> liste_1 = [1, 2, 3]
>>> listes = [liste_1, [4, 5], "abcd"]
>>>
>>> for liste in listes:
...     for elem in liste:
...         print(elem)
...     print()
...
1
2
3

4
5

a
b
c
d

4-3. Tuples

Un tuple est une collection ordonnée et non modifiable d'éléments éventuellement hétérogènes.

Éléments séparés par des virgules, et entourés de parenthèses.

 
Sélectionnez
>>> mon_tuple = ('a', 2, [1, 3])
  • L'indexage des tuples s'utilise comme celui des listes.
  • Le parcours des tuples est plus rapide que celui des listes.
  • Ils sont utiles pour définir des constantes.

Comme les chaînes de caractères, les tuples ne sont pas modifiables !

 
Sélectionnez
>>> mon_tuple.append(4) # attention ne pas modifier un tuple !
Traceback (most recent call last) :
  File "<stdin>", line 1, in <module>
AttributeError : 'tuple' object has no attribute 'append'

4-3-1. Les opérations des objets de type séquentiel

Les types prédéfinis de séquences Python (chaîne, liste et tuple) ont en commun les opérations résumées dans le tableau suivant où s et t désignent deux séquences du même type et i, j et k des entiers :

l'opération

son effet

x in s

True si s contient x, False sinon

x not in s

True si s ne contient pas x, False sinon

s + t

concaténation de s et t

s * n, n * s

n copies (superficielles) concaténées de s

s[i]

i élément de s (à partir de 0)

s[i:j]

tranche de s de i (inclus) à j (exclu)

s[i:j:k]

tranche de s de i à j avec un pas de k

len(s)

longueur de s

max(s), min(s)

plus grand, plus petit élément de s

s.index(i)

indice de la 1re occurrence de i dans s

s.count(i)

nombre d'occurrences de i dans s

4-4. Retour sur les références

Nous avons déjà vu que l'opération d'affectation, apparemment innocente, est une réelle difficulté de Python.

 
Sélectionnez
i = 1
msg = "Quoi de neuf ?"
e = 2.718

Dans l'exemple ci-dessus, les affectations réalisent plusieurs opérations :

  • création en mémoire d'un objet du type approprié (membre de droite) ;
  • stockage de la donnée dans l'objet créé ;
  • création d'un nom de variable (membre de gauche) ;
  • association de ce nom de variable avec l'objet contenant la valeur.

Une conséquence de ce mécanisme est que, si un objet modifiable est affecté à plusieurs variables, tout changement de l'objet via une variable sera visible sur tous les autres :

 
Sélectionnez
fable = ["Je", "plie", "mais", "ne", "romps", "point"]
phrase = fable

phrase[4] = "casse"

print(fable) # ['Je', 'plie', 'mais', 'ne', 'casse', 'point']

Si on veut pouvoir effectuer des modifications séparées, il faut affecter l'autre variable par une copie distincte de l'objet, soit en créant une tranche complète des séquences dans les cas simples, soit en utilisant le module copy dans les cas les plus généraux (autres conteneurs). Dans les rares occasions où l'on veut aussi que chaque élément et attribut de l'objet soit copié séparément et de façon récursive, on emploie la fonction copy.deepcopy() :

 
Sélectionnez
>>> import copy
>>> a = [1, 2, 3]
>>> b = a # une référence
>>> b.append(4)
>>> a
[1, 2, 3, 4]
>>> c = a[:] # une copie simple
>>> c.append(5)
>>> c
[1, 2, 3, 4, 5]
>>> d = copy.copy(a) # une copie de"surface"
>>> d.append(6)
>>> d
[1, 2, 3, 4, 6]
>>> a
[1, 2, 3, 4]
>>> d1 = {'a' : [1, 2], 'b' : [3, 4]}
>>> d2 = {'c' : (1, 2, 3), 'c' : (4, 5, 6)}
>>> liste_de_dicos = [d1, d2]
>>> nouvelle_liste_de_dicos = copy.deepcopy(liste_de_dicos) # copie "profonde" (ou "récursive")
>>> nouvelle_liste_de_dicos
[{'a': [1, 2], 'b': [3, 4]}, {'c': (4, 5, 6)}]

4-4-1. Complément graphique sur l'assignation

  • Assignation augmentée d'un objet non modifiable (cas d'un entier : Fig. 4.1). On a représenté l'étape de l'addition intermédiaire.

    Image non disponible
    Figure 4.1 - Assignation augmentée d'un objet non modifiable
  • Assignation augmentée d'un objet modifiable (cas d'une liste : Fig. 4.2). On a représenté l'étape de la création de la liste intermédiaire.
Image non disponible
Figure 4.2 - Assignation augmentée d'un objet modifiable

4-5. Tableaux associatifs

Un tableau associatif est un type de données permettant de stocker des couples (cle : valeur), avec un accès très rapide à la valeur à partir de la clé, la clé ne pouvant être présente qu'une seule fois dans le tableau.

Il possède les caractéristiques suivantes :

  • l'opérateur d'appartenance d'une clé (in) ;
  • la fonction taille (len()) donnant le nombre de couples stockés ;
  • il est itérable (on peut le parcourir), mais n'est pas ordonné.

Python propose le type standard dict.

4-5-1. Dictionnaires (dict)

Collection de couples clé : valeur entourée d'accolades.

Les dictionnaires constituent un type composite, mais ils n'appartiennent pas aux séquences.

Les dictionnaires sont modifiables, mais non ordonnés : les couples enregistrés n'occupent pas un ordre immuable, leur emplacement est géré par un algorithme spécifique (algorithme de hash). Le caractère non ordonné des dictionnaires est le prix à payer pour leur rapidité !

Une clé pourra être alphabétique, numérique… en fait tout type hachable (donc liste et dictionnaire exclus). Les valeurs pourront être de tout type sans exclusion.

4-5-1-a. Exemples de création

 
Sélectionnez
>>> d1 = {} # dictionnaire vide. Autre notation : d1 = dict()
>>> d1["nom"] = 3
>>> d1["taille"] = 176
>>> d1
{'nom': 3, 'taille': 176}
>>>
>>> d2 = {"nom": 3, "taille": 176} # définition en extension
>>> d2
{'nom': 3, 'taille': 176}
>>>
>>> d3 = {x: x**2 for x in (2, 4, 6)} # définition en compréhension
>>> d3
{2: 4, 4: 16, 6: 36}
>>>
>>> d4 = dict(nom=3, taille=176) # utilisation de paramètres nommés
>>> d4
{'taille': 176, 'nom': 3}
>>>
>>> d5 = dict([("nom", 3), ("taille", 176)]) # utilisation d'une liste de couples clés/valeurs
>>> d5
{'nom': 3, 'taille': 176}

4-5-1-b. Méthodes

Quelques méthodes applicables aux dictionnaires :

 
Sélectionnez
>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'sape': 4139, 'jack': 4098, 'guido': 4127}
>>> tel['jack']
4098
>>> del tel['sape']
>>> tel['irv'] = 4127
>>> tel
{'jack': 4098, 'irv': 4127, 'guido': 4127}
>>>
>>> tel.keys()
['jack', 'irv', 'guido']
>>> sorted(tel.keys())
['guido', 'irv', 'jack']
>>> sorted(tel.values())
[4098, 4127, 4127]
>>> 'guido' in tel, 'jack' not in tel
(True, False)

4-6. Ensembles (set)

Un ensemble est une collection itérable non ordonnée d'éléments hachables uniques.

Donc un set est la transposition informatique de la notion d'ensemble mathématique.

En Python, il existe deux types d'ensembles, les ensembles modifiables : set et les ensembles non modifiables : frozenset. On retrouve ici les mêmes différences qu'entre les listes et les tuples.

 
Sélectionnez
>>> X = set('spam')
>>> Y = set('pass')
>>> X
{'s', 'p', 'm', 'a'}
>>> Y # pas de duplication : qu'un seul 's'
{'s', 'p', 'a'}
>>> 'p' in X
True
>>> 'm' in Y
False
>>> X - Y # ensemble des éléments de X qui ne sont pas dans Y
{'m'}
>>> Y - X # ensemble des éléments de Y qui ne sont pas dans X
set()
>>> X ^ Y # ensemble des éléments qui sont soit dans X soit dans Y
{'m'}
>>> X | Y # union
{'s', 'p', 'm', 'a'}
>>> X & Y # intersection
{'s', 'p', 'a'}
Image non disponible
Figure 4.3 - Opérations sur les ensembles

4-7. Fichiers textuels

4-7-1. Introduction

On rappelle que l'ordinateur n'exécute que les programmes présents dans sa mémoire volatile (la RAM). Pour conserver durablement des informations, il faut utiliser une mémoire permanente par exemple le disque dur, la clé USB, le DVD… sur lesquels le système d'exploitation organise les données sous la forme de fichiers.

Comme la plupart des langages, Python utilise classiquement la notion de fichier.

Nous limiterons nos exemples aux fichiers textuels (lisibles par un éditeur), mais signalons que les fichiers stockés en codage binaire sont plus compacts et plus rapides à gérer (utiles pour les grands volumes de données).

4-7-2. Gestion des fichiers

4-7-2-a. Ouverture et fermeture des fichiers

Principaux modes d'ouverture des fichiers textuels(12) :

 
Sélectionnez
f1 = open("monFichier_1", "r", encoding='utf8') #"r" mode lecture
f2 = open("monFichier_2", "w", encoding='utf8') #"w" mode écriture
f3 = open("monFichier_3", "a", encoding='utf8') #"a" mode ajout

Python utilise les fichiers en mode texte par défaut (mode t). Pour les fichiers binaires, il faut préciser le mode b.

Le paramètre optionnel encoding assure les conversions entre les types byte (c'est-à-dire des tableaux d'octets), format de stockage des fichiers sur le disque, et le type str (qui, en Python 3, signifie toujours Unicode), manipulé lors des lectures et écritures. Il est prudent de toujours l'utiliser.

Les encodages les plus fréquents sont utf8 (c'est l'encodage à privilégier en Python 3), latin1, ASCII

Tant que le fichier n'est pas fermé(13), son contenu n'est pas garanti sur le disque.

Une seule méthode de fermeture :

 
Sélectionnez
f1.close()

4-7-2-b. Écriture séquentielle

Le fichier sur disque est considéré comme une séquence de caractères qui sont ajoutés à la suite, au fur et à mesure que l'on écrit dans le fichier.

Méthodes d'écriture :

 
Sélectionnez
f = open("truc.txt", "w", encoding='utf8')
s = 'toto\n'
f.write(s) # écrit la chaîne s dans f
l = ['a', 'b', 'c']
f.writelines(l) # écrit les chaînes de la liste l dans f
f.close()

f2 = open("truc2.txt", "w", encoding='utf8')
print("abcd", file=f2) # utilisation de l'option file
f2.close()

4-7-2-c. Lecture séquentielle

En lecture, la séquence de caractères qui constitue le fichier est parcourue en commençant au début du fichier et en avançant au fur et à mesure des lectures.

Méthodes de lecture d'un fichier en entier :

 
Sélectionnez
>>> f = open("truc.txt", "r", encoding='utf8')
>>> s = f.read() # lit tout le fichier --> chaîne
>>> f.close()
>>> f = open("truc.txt", "r", encoding='utf8')
>>> s = f.readlines() # lit tout le fichier --> liste de chaînes
>>> f.close()

Méthodes de lecture d'un fichier partiel :

 
Sélectionnez
>>> f = open("truc.txt", "r", encoding='utf8')
>>> s = f.read(3) # lit au plus n octets --> chaîne
>>> s = f.readline() # lit la ligne suivante --> chaîne
>>> f.close()
>>>
>>> # Affichage des lignes d'un fichier une à une
>>> f = open("truc.txt", encoding='utf8') # mode"r" par défaut
>>> for ligne in f:
...     print(ligne)
...
>>> f.close()

4-8. Itérer sur les conteneurs

Les techniques suivantes sont classiques et très utiles.

Obtenir clés et valeurs en bouclant sur un dictionnaire :

 
Sélectionnez
knights = {"Gallahad" : "the pure", "Robin" : "the brave"}
for k, v in knights.items() :
    print(k, v)
# Gallahad the pure
# Robin the brave

Obtenir indice et élément en bouclant sur une liste :

 
Sélectionnez
>>> for i, v in enumerate(["tic", "tac", "toe"]):
...     print(i, '->', v)
...
0 -> tic
1 -> tac
2 -> toe

Boucler sur deux séquences (ou plus) appariées :

 
Sélectionnez
>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['Lancelot', 'the Holy Grail', 'blue']
>>> for question, answer in zip(questions, answers):
...     print('What is your', question, '? It is', answer)
...
What is your name ? It is Lancelot
What is your quest ? It is the Holy Grail
What is your favorite color ? It is blue

Obtenir une séquence inversée (la séquence initiale est inchangée) :

 
Sélectionnez
for i in reversed(range(1, 10, 2)) :
    print(i, end="") # 9 7 5 3 1

Obtenir une séquence triée à éléments uniques (la séquence initiale est inchangée) :

 
Sélectionnez
basket = ["apple", "orange", "apple", "pear", "orange", "banana"]
for f in sorted(set(basket)) :
    print(f, end="") # apple banana orange pear

4-9. Affichage formaté

La méthode format() permet de contrôler finement la création de chaînes formatées. On l'utilisera pour un affichage via print(), pour un enregistrement via f.write(), ou dans d'autres cas.

Remplacements simples :

 
Sélectionnez
print("{} {} {}".format("zéro", "un", "deux")) # zéro un deux

# formatage d'une chaîne pour usages ultérieurs
chain = "{2} {0} {1}".format("zéro", "un", "deux")

print(chain) # affichage : deux zéro un
with open("test.txt", "w", encoding="utf8") as f :
    f.write(chain) # enregistrement dans un fichier

print("Je m'appelle {}".format("Bob")) # Je m'appelle Bob
print("Je m'appelle {{{}}}".format("Bob")) # Je m'appelle {Bob}
print("{}".format("-"*10)) # ----------

Remplacements avec champs nommés :

 
Sélectionnez
a, b = 5, 3
print("The story of {c} and {d}".format(c=a+b, d=a-b)) # The story of 8 and 2

Formatages à l'aide de liste :

 
Sélectionnez
stock = ['papier', 'enveloppe', 'chemise', 'encre', 'buvard']
print("Nous avons de l'{0[3]} et du {0[0]} en stock\n".format(stock)) # Nous avons de l'encre et du papier en stock

Formatages à l'aide de dictionnaire :

 
Sélectionnez
print("My name is {0[name]}".format(dict(name='Fred'))) # My name is Fred

d = dict(poids = 12000, animal = 'éléphant')
print("L'{0[animal]} pèse {0[poids]} kg\n".format(d)) # L'éléphant pèse 12000 kg

Remplacement avec attributs nommés :

 
Sélectionnez
import math
import sys

print("math.pi = {.pi}, epsilon = {.float_info.epsilon}".format(math, sys))
# math.pi = 3.14159265359, epsilon = 2.22044604925e-16

Conversions textuelles, str() et repr()(14) :

 
Sélectionnez
>>> print("{0!s} {0!r}".format("texte\n"))
texte
   'texte\n'

Formatages numériques :

 
Sélectionnez
s = "int :{0:d} ; hex : {0:x} ; oct : {0:o} ; bin : {0:b}".format(42)
print(s) # int :42; hex : 2a ; oct : 52; bin : 101010
s = "int :{0:d} ; hex : {0:#x} ; oct : {0:#o} ; bin : {0:#b}".format(42)
print(s) # int :42; hex : 0x2a ; oct : 0o52 ; bin : 0b101010

n = 100
pi = 3.1415926535897931
k = -54

print("{ :.4e}".format(pi)) # 3.1416e+00
print("{ :g}".format(pi)) # 3.14159
print("{ :.2%}".format(n/(47*pi))) # 67.73%

msg = "Résultat sur { :d} échantillons : { :.2f}".format(n, pi)
print(msg) # Résultat sur 100 échantillons : 3.14

msg = "{0.real} et {0.imag} sont les composantes du complexe {0}".format(3-5j)
print(msg) # 3.0 et -5.0 sont les composantes du complexe (3-5j)

print("{ :+d} { :+d}".format(n, k)) # +100 -54 (on force l'affichage du signe)

print("{ :,}".format(1234567890.123)) # 1,234,567,890.12

Formatages divers :

 
Sélectionnez
>>> s = "The sword of truth"
>>> print("[{}]".format(s))
[The sword of truth]
>>> print("[{:25}]".format(s))
[The sword of truth       ]
>>> print("[{:>25}]".format(s))
[       The sword of truth]
>>> print("[{:^25}]".format(s))
[   The sword of truth    ]
>>> print("[{:-^25}]".format(s))
[---The sword of truth----]
>>> print("[{:.<25}]".format(s))
[The sword of truth.......]
>>> lng = 12
>>> print("[{}]".format(s[:lng]))
[The sword of]
>>> m = 123456789
>>> print("{:0=12}".format(m))
000123456789

précédentsommairesuivant
« tuple » n'est pas vraiment un anglicisme, mais plutôt un néologisme informatique.
Remarquez que l'on précise l'encoding. Ceci sera justifié ultérieurement (cf. Jeux de caractères et encodageJeux de caractères et encodage).
Ou bien flushé par un appel à la méthode flush().
str() est un affichage orienté utilisateur alors que repr() est une représentation littérale.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2015 Kordeo. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.