Variables et types de données

  • Variables
  • Types de données
  • Fichiers

Contenu sous licence CC BY-SA 4.0

Langage python et sa syntaxe

Variables et affectation

Pour accéder à une donnée, on lui donne un nom que l'on appelle variable. Cette opération s'appelle une affectation (ou assignation) et se fait avec l'opérateur =.

variable_x = donnee_x

signifie qu'on affecte la donnee_x à la variable_x.

Exécutez la cellule suivante pour définir trois variables nommées : age, prenom et taille.

In [1]:
# Par exemple: donnons la valeur 23 à la variable 'age'
age = 23
# Les variables peuvent se référer à divers types de données : des chaînes de caractères...
prenom = 'Julien'
# Des nombres réels, etc...
taille = 1.83

Le mécanisme d'affectation en détail

Lors de l'affectation x = donnee_x, Python :

  1. crée et mémorise le nom de variable x
  2. crée un objet dont le type dépend de la nature de la donnée et y stocke la valeur particulière donnee_x
  3. établit une référence entre le nom de la variable x et l'emplacement mémoire de donnee_x. Cette référence est mémorisée dans l'espace de nom.

Accéder à la valeur d'une variable

Pour se servir de la donnée référencée par une variable, il suffit d'utiliser le nom cette variable.

La fonction print() affiche à l'écran ce qui lui est passé en paramètre. On peut lui donner plusieurs paramètres séparés par des virgules : print() les affichera tous, séparés par un espace.

In [2]:
print('Julien', 23, 1.83)
print(prenom, 'a', age, 'ans, et mesure', taille, 'mètre')
Julien 23 1.83
Julien a 23 ans, et mesure 1.83 mètre

Les variables peuvent changer et ainsi se référer à une autre donnée.

In [3]:
age = 23
print(age)
age = 24
print(age)
23
24

L'affectation du point de vue de l'objet

La notion d'objet

En python, toute donnée est contenue dans un objet. En programmation, un objet est un conteneur qui regroupe :

  • des données
  • les méthodes pour interagir avec ces données

Exemple de l'objet de type entier relatif (int) :

  • sa donnée : la valeur du nombre entier
  • ses méthodes : les opérations mathématiques, la conversion vers les chaînes de caractères, etc.

Affecter une valeur à une variable revient à nommer un objet, c'est-à-dire référencer cet objet par un nom.

Exemple avec l'entier 7 :

  • pour Python, 7 est l'objet de type entier (int) dont la donnée est le nombre $~7$
  • lorsqu'on écrit 7 dans un programme, Python crée l'objet correspondant et lui affecte un identifiant unique dans l'espace de nom courant.
  • cet identifiant est renvoyé par la fonction intrinsèque id() :
In [4]:
print(id(7))
94378619786344
x = 7

signifie qu'on nomme l'objet 7 avec la variable x. Autrement dit, x devient une référence vers cet objet.

In [5]:
print(id(7))
x = 7
print(id(x))
y = x
print(id(y))  # y référence le même objet que x
94378619786344
94378619786344
94378619786344

Le type

Les variables n'ont pas de type propre : c'est la donnée qui est typée, pas la variable qui la référence. Une variable peut donc faire référence à une donnée d'un autre type après une nouvelle affectation.

La fonction type() retourne le type effectif de la donnée passée en paramètre.

In [6]:
# Des nombres
age = 23
print(type(age))
<class 'int'>
In [7]:
# Les variables peuvent aussi changer de type : chaîne de caractères
age = 'vingt quatre ans'
print(type(age))
<class 'str'>
In [8]:
# Sans limites...
age = 24.5
print(type(age))
<class 'float'>
In [9]:
# Attention aux pièges...
age = '25'
print(type(age))
<class 'str'>

Une variable peut être initialisée avec des valeurs constantes, comme vu précédement, mais aussi à partir d'autres variables ou de valeurs retournées par des opérations, des fonctions, etc.

Exemple : La fonction max() retourne le plus grand de ses paramètres.

In [10]:
a = 1
b = a
c = a * 2
d = max(a, 2, 3, c)
print(a, b, c, d)
1 1 2 3

Les variables, une fois définies dans une cellule exécutée, continuent d'exister dans les suivantes car toutes les cellules sont connectées à la même instance du noyau python.

Note : En cas de redémarrage du notebook, toutes les variables existantes sont détruites, il faut donc ré-exécuter les cellules qui les définissent si l'on veut de nouveau pouvoir les utiliser.

In [11]:
abcd = 1234

Ici, la variable nommée abcd survit, d'une cellule à la suivante...

In [12]:
print(abcd)
1234

Si on veut faire disparaître une variable, on peut utiliser l'instruction del.

In [13]:
# Cette cellule génère une erreur
a = 2
print(a)
del a
print(a)
2
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[13], line 5
      3 print(a)
      4 del a
----> 5 print(a)

NameError: name 'a' is not defined

Note : del est aussi utilisé pour enlever des éléments dans des conteneurs modifiables (listes, dictionnaires). Nous aborderons ce sujet plus tard.

Types de données

Types de base

  • None
  • Booléens
  • Numériques
    • entiers
    • flottants
    • complexes

Séquences

  • Chaines de caractères
  • listes
  • tuples

Conteneurs

  • Dictionnaires
  • Ensembles

Fichiers

Types de base

None

  • Il existe dans python un type de données particulier : None.
  • None représente un objet sans valeur. On s'en sert comme valeur de retour en cas d'erreur ou pour représenter un cas particulier.
  • None est équivalent à NULL en Java et en C.
In [14]:
a = None
print(a)
print(type(a))  
None
<class 'NoneType'>

Booléens

Les booléens ne peuvent avoir que deux valeurs :

True, False

On peut utiliser la fonction bool() pour construire un booléen.

Dans un contexte booléen, toutes ces valeurs sont équivalentes à False :

  • None
  • le zéro des types numériques, par exemple : 0, 0.0, 0j.
  • les séquences vides, par exemple : '', (), [].
  • les dictionnaires vides, par exemple, {}.

Tout le reste est équivalent à True :

  • une valeur numérique différente de zéro
  • une séquence non vide
  • un dictionnaire non vide

Exemples de constructions de valeurs booléennes à partir d'autres types

In [15]:
print(bool(None), bool())
print(bool(0), bool(1))
print(bool(0.0), bool(0.5))
print(bool(0j), bool(3j))
print(bool(''), bool('abc'))
print(bool(()), bool((1, 0.5, 'toto')))
print(bool([]), bool([None]))
print(bool({}), bool({'ane': True, 'chat': True}))
False False
False True
False True
False True
False True
False True
False True
False True

Exemple d'utilisation d'un contexte booléen

In [16]:
Am_I_OK = True
if Am_I_OK:
    print('OK')
else:
    print('KO')
print(Am_I_OK)
print(type(Am_I_OK))
OK
True
<class 'bool'>

Exercice :

  1. Supposons que vous soyez malade, mettez Am_I_OK à la valeur False puis réexecutez la cellule.
  2. Essayez avec d'autres types : list, None, nombres, etc...

Numériques

Entiers

La taille est illimitée.

In [17]:
# Il n'y a plus de distinction entre les entiers "courts" et les entiers "longs"
entier = 4
print(entier)
print(type(entier))
# Ce nombre nécéssite 131 bits
entier = 1415926535897932384626433832795028841971
print(entier)
print(type(entier))
4
<class 'int'>
1415926535897932384626433832795028841971
<class 'int'>

Ou plus exactement, la taille n'est pas limitée par le langage mais par la mémoire disponible sur le système.

Note : En python version < 3, il existait deux types distincts int et long...

  • On peut utiliser la fonction interne int() pour créer des nombres entiers.
  • int() peut créer des entiers à partir de leur représentation sous forme de chaîne de caractères
  • On peut aussi spécifier la base :
In [18]:
entier = int(12)
print(entier)
print(type(entier))
entier = int('13')
print(entier)
print(type(entier))
entier = int('0xFF', 16)
print(entier)
print(type(entier))
12
<class 'int'>
13
<class 'int'>
255
<class 'int'>

Flottants (réels 64 bits)

Pour créer des nombres réels (en virgule flottante), on peut utiliser la fonction interne float().

La précision est limitée à 16 chiffres significatifs.

In [19]:
pi_approx = 3.141592653589793 2
print(pi_approx) 
print(type(pi_approx))
print('{:.16f}'.format(pi_approx))
tropgros = float('Infinity')
print(type(tropgros))
print(tropgros)
  Cell In[19], line 1
    pi_approx = 3.141592653589793 2
                                  ^
SyntaxError: invalid syntax

Flottants

Attention ! Python autorise un affichage plus long que la précision des flottants mais tous les chiffres après le 16ème chiffre significatif sont faux :

In [20]:
# On demande 20 chiffres après la virgule, alors que 16 seulement sont exacts
print('{:.20f}'.format(pi_approx))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[20], line 2
      1 # On demande 20 chiffres après la virgule, alors que 16 seulement sont exacts
----> 2 print('{:.20f}'.format(pi_approx))

NameError: name 'pi_approx' is not defined

Attention à ne pas effectuer des opérations interdites...

In [21]:
# Cette cellule génère une erreur
print(3.14 / 0)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Cell In[21], line 2
      1 # Cette cellule génère une erreur
----> 2 print(3.14 / 0)

ZeroDivisionError: float division by zero
In [22]:
# Cette cellule génère une erreur
print(34 % 0)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Cell In[22], line 2
      1 # Cette cellule génère une erreur
----> 2 print(34 % 0)

ZeroDivisionError: integer modulo by zero
In [23]:
# Cette cellule génère une erreur
print(27 // 0.0)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Cell In[23], line 2
      1 # Cette cellule génère une erreur
----> 2 print(27 // 0.0)

ZeroDivisionError: float floor division by zero
In [24]:
# Cette cellule génère une erreur
print(1 + None)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[24], line 2
      1 # Cette cellule génère une erreur
----> 2 print(1 + None)

TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

Complexes

Les nombres complexes, à deux dimensions, peuvent être créés en utilisant le suffixe j à la fin d'un entier ou réel ou en utilisant la fonction interne complex()

In [25]:
c1 = 1 + 2j
print('représentation :', c1)
print(type(c1))
c2 = .3j
print(c2)
représentation : (1+2j)
<class 'complex'>
0.3j

Séquences

Les séquences sont des conteneurs d'objets où les objets référencés sont ordonnés.

Python supporte nativement trois types de séquences :

  • les chaînes de caractères
  • les listes
  • les tuples

Chaînes de caractères

Pour le traitement de données textuelles, python utilise les chaînes de caractères.

Pour délimiter le texte on utilise des guillemets " (double-quote) ou des apostrophes ' (single-quote).

In [26]:
mois1 = 'janvier'
mois2 = "février"
print(mois1, mois2)
janvier février

Les deux formes sont très utiles car elles permettent d'utiliser des guillemets ou des apostrophes dans des chaînes de caractères de manière simple.

In [27]:
arbre = "l'olivier"
print(arbre)
cuisson_pates = "huit minutes (8')"
print(cuisson_pates)
record_100m = 'neuf secondes et 58 centièmes (9"58)'
print(record_100m)
l'olivier
huit minutes (8')
neuf secondes et 58 centièmes (9"58)

Sinon, pour avoir une apostrophe ou un guillemet dans une chaîne de caractères, il faut le faire précéder d'un \ (backslash). Ce qui est beaucoup moins lisible, mais parfois obligatoire (par exemple une chaîne avec à la fois des guillemets et des apostrophes).

In [28]:
arbre = 'l\'alisier'
pates = '8\''
record = "9\"58"
print(arbre, pates, record)
duel = 'guillemet: " et apostrophes: \' peuvent être utilisés dans une même chaîne...'
print(duel)
multi = '''Dans une "triplequoted" (voire plus loin), on peut (presque) tout utiliser: `"“ ”,'"«»'"' et ça ne pose pas de problème...'''
print(multi)
l'alisier 8' 9"58
guillemet: " et apostrophes: ' peuvent être utilisés dans une même chaîne...
Dans une "triplequoted" (voire plus loin), on peut (presque) tout utiliser: `"“ ”,'"«»'"' et ça ne pose pas de problème...

Caractères spéciaux

Il est possible de définir des chaînes de caractères qui contiennent des caractères spéciaux. Ils sont introduits par des séquences de deux caractères dont le premier est \. On l'appelle le caractère d'échappement.

  • retour à la ligne : \n
  • tabulation : \t
  • backslash : \\
  • un caractère unicode avec son code : \uXXXX (où les XXXX sont le code hexadécimal représentant ce caractère)

Plus d'information dans la documentation officielle

In [29]:
print("Une belle présentation, c'est :\n\t- bien ordonné\n\t- aligné\n\t- même s'il y en a plein\nEt c'est plus joli.")
print("Une belle présentation, c'est :")
print('\t- bien ordonné')
print('\t- aligné') 
print("\t- même s'il y en a plein\nEt c'est plus joli.")
Une belle présentation, c'est :
	- bien ordonné
	- aligné
	- même s'il y en a plein
Et c'est plus joli.
Une belle présentation, c'est :
	- bien ordonné
	- aligné
	- même s'il y en a plein
Et c'est plus joli.

Chaînes multilignes

Pour écrire plusieurs lignes d'une façon plus lisible, il existe les chaînes multilignes :

In [30]:
# L'équivalent est :
print("""\
Une belle présentation, c'est :
\t- bien ordonné
\t- aligné
\t- même s'il y en a plein
Et c'est plus joli.""")
Une belle présentation, c'est :
	- bien ordonné
	- aligné
	- même s'il y en a plein
Et c'est plus joli.

Exercice : enlevez le caractère \ de la 2ème ligne dans la cellule ci-dessus, et comparez le résultat à celui de la cellule de code précédente (3 cellules plus haut)

Les deux formes de délimiteurs sont aussi utilisables : guillemets triples ou apostrophes triples.

In [31]:
multi1 = '''m
a
r
s est un mois "multiligne"'''
print(multi1, '\n')

multi2 = """a
v
r
i
l l'est aussi"""
print(multi2)
m
a
r
s est un mois "multiligne" 

a
v
r
i
l l'est aussi

Unicode

En python 3 , toutes les chaînes de caractères sont unicode, ce qui permet d'utiliser des alphabets différents, des caractères accentués ou des pictogrammes, etc.

Exemples de caractères spéciaux :

In [32]:
unicode_str = "Les échecs (♔♕♖♗♘♙), c'est \u263A"
print(unicode_str)
japanese_str = 'Du japonais : ウェブ'
print(japanese_str)
mix_str = '你好 kollha दुनिया'
print('"' + mix_str + '"', 'veut dire: "bonjour tout le monde"')
Les échecs (♔♕♖♗♘♙), c'est ☺
Du japonais : ウェブ
"你好 kollha दुनिया" veut dire: "bonjour tout le monde"

Pour une liste de caractères unicode, voir ici.

Chaînes brutes (raw strings)

Il s'agit de chaînes dans lesquelles les séquences d'échappement ne sont pas remplacées : r'...', r'''...''', etc.

In [33]:
normal_str = "chaîne normale: \n est un retour à la ligne, \t est une tabulation"
print(normal_str)

raw_str = r"chaîne RAW: \n est un retour à la ligne, \t est une tabulation"
print(raw_str)
chaîne normale: 
 est un retour à la ligne, 	 est une tabulation
chaîne RAW: \n est un retour à la ligne, \t est une tabulation

Concaténation

Plusieurs chaînes de caractères contigües sont rassemblées.

In [34]:
b = 'a' 'z' 'e' 'r' 't' 'y'
print(b)
azerty

On peut mélanger les genres.

In [35]:
a = 'une chaine qui est \t' r'''la somme de \n ''' """plusieurs morceaux..."""
print(a)
une chaine qui est 	la somme de \n plusieurs morceaux...

On peut utiliser la fonction str() pour créer une chaîne de caractère à partir d'autres objets.

In [36]:
a = 23
ch_a = str(a)
print(type(a), a)
print(type(ch_a), repr(ch_a))
a = 3.14
ch_a = str(a)
print(type(a), a)
print(type(ch_a), repr(ch_a))
<class 'int'> 23
<class 'str'> '23'
<class 'float'> 3.14
<class 'str'> '3.14'

On ne peut pas mélanger les guillemets et les apostrophes pour délimiter une chaîne de caractères.

In [37]:
# Cette cellule génère une erreur
a = "azerty'
  Cell In[37], line 2
    a = "azerty'
        ^
SyntaxError: unterminated string literal (detected at line 2)
In [38]:
# Cette cellule génère une erreur
a = 'azerty"
  Cell In[38], line 2
    a = 'azerty"
        ^
SyntaxError: unterminated string literal (detected at line 2)

Exercice : corrigez les deux cellules ci dessus.

Le formatage de chaîne de caractère avec format()

On peut formater du texte, c'est à dire utiliser une chaîne de caractères qui va servir de modèle pour en fabriquer d'autres. Historiquement, il existe plusieurs méthodes. Nous ne voyons ici qu'une utilisation basique de la méthode format().

format() remplace les occurences de '{}' par des valeurs qu'on lui spécifie en paramètre. Le type des valeurs passées n'est pas important, une représentation sous forme de chaîne de caractère sera automatiquement créée, avec la fonction str().

'Bonjour {} !'.format('le monde')
In [39]:
variable_1 = 27
variable_2 = 'vingt huit'
ch_modele = 'Une chaine qui contient un {} ainsi que {} et là {}'
ch_modele.format('toto', variable_1, variable_2)
Out[39]:
'Une chaine qui contient un toto ainsi que 27 et là vingt huit'

Les spécifications de format

Des indicateurs peuvent être fournis à la méthode format() pour spécifier le type de donnée à intégrer et la manière de formater sa représentation.

  • :d pour des entiers
  • :s pour des chaînes de caractères
  • :f pour des nombres flottants
  • :x pour un nombre entier affiché en base hexadécimale
  • :o pour un nombre entier affiché en base octale
  • :e pour un nombre affiché en notation exponentielle
In [40]:
import math
a = 27
ch = """un entier : {:d},
une chaîne : {:s},
un flottant avec une précision spécifiée : {:.02f}"""
print(type(ch))
print(ch)
print(ch.format(a, 'Arte', math.pi))
print('Des hexadécimaux: {:x} {:x} {:x} {:x}'.format(254, 255, 256, 257))
print('Des octaux: {:o} {:o} {:o} {:o}'.format(254, 255, 256, 257))
print('Des nombres en notation exponentielle {:e}'.format(2**64))
<class 'str'>
un entier : {:d},
une chaîne : {:s},
un flottant avec une précision spécifiée : {:.02f}
un entier : 27,
une chaîne : Arte,
un flottant avec une précision spécifiée : 3.14
Des hexadécimaux: fe ff 100 101
Des octaux: 376 377 400 401
Des nombres en notation exponentielle 1.844674e+19

Attention : Si le type de la donnée passée ne correspond pas à la séquence de formatage, python va remonter une erreur.

In [41]:
# Cette cellule génère une erreur
variable_3 = 'une chaine de caracteres'
# Exemple d'erreur de type : on fournit une chaîne de caractères
# alors que la méthode attend un entier
print('on veut un entier : {:d}'.format(variable_3))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[41], line 5
      2 variable_3 = 'une chaine de caracteres'
      3 # Exemple d'erreur de type : on fournit une chaîne de caractères
      4 # alors que la méthode attend un entier
----> 5 print('on veut un entier : {:d}'.format(variable_3))

ValueError: Unknown format code 'd' for object of type 'str'

On peut se servir de cette fonctionnalité pour indenter du texte de taille variable.

In [42]:
print("""
Alignons à droite les animaux:
Un animal : {:>8s}.
Un animal : {:>8s}.
Un animal : {:>18s}, qui se croit plus malin que les autres.
Un animal : {:>8s}.
Un animal : {:>8s}.""".format('âne', 'becasse', 'chat', 'dinde', 'elephant'))
Alignons à droite les animaux:
Un animal :      âne.
Un animal :  becasse.
Un animal :               chat, qui se croit plus malin que les autres.
Un animal :    dinde.
Un animal : elephant.

Exercice : remettez le chat à sa place.

f-string

Depuis Python 3.6, il existe une autre syntaxe appelée f-string qui ajoute de la concision et de la lisibilité :

f"La {<variable>:<format>} est nommée dans la chaîne."
In [43]:
print('Soit {:.03f} la valeur de pi sur 3 décimales.'.format(math.pi))
# devient
print(f'Soit {math.pi:.03f} la valeur de pi sur 3 décimales.')
Soit 3.142 la valeur de pi sur 3 décimales.
Soit 3.142 la valeur de pi sur 3 décimales.

Remarques :

  • cette syntaxe n'est pas toujours utilisable
  • le code sera incompatible avec python < 3.6

Pour plus d'informations sur le formatage de chaînes de caractères, voir la doc Python correspondante.

Listes

  • Une liste est un objet pouvant contenir d'autres objets
  • Ces objets, appelés éléments, sont ordonnés de façon séquentielle, les uns à la suite des autres
  • C'est un conteneur dynamique dont le nombre et l'ordre des éléments peuvent varier

On crée une liste en délimitant par des crochets [] les éléments qui la composent :

In [44]:
L = ['egg', 'spam', 'spam', 'spam', 'bacon']
print(L, 'est de type', type(L))
['egg', 'spam', 'spam', 'spam', 'bacon'] est de type <class 'list'>

Une liste peut contenir n'importe quel type d'objets.

In [45]:
L0 = [1, 2]
L1 = []
L2 = [None, True, False, 0, 1, 2**64, 3.14, '', 0+1j, 'abc']
L3 = [[1, 'azerty'], L0]
print(L0, L1)
print(L2)
print(L3)
[1, 2] []
[None, True, False, 0, 1, 18446744073709551616, 3.14, '', 1j, 'abc']
[[1, 'azerty'], [1, 2]]

On peut utiliser la fonction list() pour créer une liste a partir d'autres séquences ou objets.

In [46]:
a = list()
b = list('bzzzzzt')
print(a)
print(b)
[]
['b', 'z', 'z', 'z', 'z', 'z', 't']

On accède aux éléments d'une liste grâce à un indice. Le premier élément est indicé 0.

In [47]:
print(L)
print(L[0])
print(L[4])
['egg', 'spam', 'spam', 'spam', 'bacon']
egg
bacon

Un dépassement d'indice produit une erreur :

In [48]:
# Cette cellule génère une erreur
print(L[10])
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[48], line 2
      1 # Cette cellule génère une erreur
----> 2 print(L[10])

IndexError: list index out of range

Les listes sont dites muables : on peut modifier la séquence de ses éléments.

Je remplace le deuxième élément :

In [49]:
L[1] = 'tomatoes'
print(L)
L[3] = 9
print(L)
['egg', 'tomatoes', 'spam', 'spam', 'bacon']
['egg', 'tomatoes', 'spam', 9, 'bacon']

Méthodes associées aux listes

Méthodes ne modifiant pas la liste
  • La longueur d'une liste est donnée par fonction len()
  • L.index(elem) renvoie l'indice de l'élément elem (le 1er rencontré)
Méthodes modifiant la liste
  • L.append() ajoute un élément à la fin
  • L.pop() retourne le dernier élément et le retire de la liste
  • L.sort() trie
  • L.reverse() inverse l'ordre

Plus d'infos dans la doc officielle.

Exemples

In [50]:
L = ['egg', 'spam', 'spam', 'spam', 'bacon']
print('len() renvoie:', len(L))
L.append('spam') # Ne renvoie pas de valeur
print('Après append():', L)
print('len() renvoie:', len(L))
len() renvoie: 5
Après append(): ['egg', 'spam', 'spam', 'spam', 'bacon', 'spam']
len() renvoie: 6
In [51]:
print('pop() renvoie:', L.pop())
print('Après pop():', L)
pop() renvoie: spam
Après pop(): ['egg', 'spam', 'spam', 'spam', 'bacon']
In [52]:
L.reverse() # Ne renvoie pas de valeur
print('Après reverse():', L)
Après reverse(): ['bacon', 'spam', 'spam', 'spam', 'egg']
In [53]:
print('index() renvoie:', L.index('egg'))
index() renvoie: 4
In [54]:
L.remove('spam') # Ne renvoie pas de valeur
print('Après remove:', L)
Après remove: ['bacon', 'spam', 'spam', 'egg']

Dans les exemples précédents, remarquez la syntaxe qui permet d'appliquer une méthode à un objet :

objet.methode()

Ici, .methode() est une fonction propre au type de objet. Si .methode() existe pour un autre type, elle n'a pas forcément le même comportement.

Pour obtenir la liste des méthodes associées aux listes, on peut utiliser la fonction interne help() :

In [55]:
help(L) # ou aussi help([])
Help on list object:

class list(object)
 |  list(iterable=(), /)
 |  
 |  Built-in mutable sequence.
 |  
 |  If no argument is given, the constructor creates a new empty list.
 |  The argument must be an iterable if specified.
 |  
 |  Methods defined here:
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __contains__(self, key, /)
 |      Return key in self.
 |  
 |  __delitem__(self, key, /)
 |      Delete self[key].
 |  
 |  __eq__(self, value, /)
 |      Return self==value.
 |  
 |  __ge__(self, value, /)
 |      Return self>=value.
 |  
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |  
 |  __getitem__(...)
 |      x.__getitem__(y) <==> x[y]
 |  
 |  __gt__(self, value, /)
 |      Return self>value.
 |  
 |  __iadd__(self, value, /)
 |      Implement self+=value.
 |  
 |  __imul__(self, value, /)
 |      Implement self*=value.
 |  
 |  __init__(self, /, *args, **kwargs)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  __iter__(self, /)
 |      Implement iter(self).
 |  
 |  __le__(self, value, /)
 |      Return self<=value.
 |  
 |  __len__(self, /)
 |      Return len(self).
 |  
 |  __lt__(self, value, /)
 |      Return self<value.
 |  
 |  __mul__(self, value, /)
 |      Return self*value.
 |  
 |  __ne__(self, value, /)
 |      Return self!=value.
 |  
 |  __repr__(self, /)
 |      Return repr(self).
 |  
 |  __reversed__(self, /)
 |      Return a reverse iterator over the list.
 |  
 |  __rmul__(self, value, /)
 |      Return value*self.
 |  
 |  __setitem__(self, key, value, /)
 |      Set self[key] to value.
 |  
 |  __sizeof__(self, /)
 |      Return the size of the list in memory, in bytes.
 |  
 |  append(self, object, /)
 |      Append object to the end of the list.
 |  
 |  clear(self, /)
 |      Remove all items from list.
 |  
 |  copy(self, /)
 |      Return a shallow copy of the list.
 |  
 |  count(self, value, /)
 |      Return number of occurrences of value.
 |  
 |  extend(self, iterable, /)
 |      Extend list by appending elements from the iterable.
 |  
 |  index(self, value, start=0, stop=9223372036854775807, /)
 |      Return first index of value.
 |      
 |      Raises ValueError if the value is not present.
 |  
 |  insert(self, index, object, /)
 |      Insert object before index.
 |  
 |  pop(self, index=-1, /)
 |      Remove and return item at index (default last).
 |      
 |      Raises IndexError if list is empty or index is out of range.
 |  
 |  remove(self, value, /)
 |      Remove first occurrence of value.
 |      
 |      Raises ValueError if the value is not present.
 |  
 |  reverse(self, /)
 |      Reverse *IN PLACE*.
 |  
 |  sort(self, /, *, key=None, reverse=False)
 |      Sort the list in ascending order and return None.
 |      
 |      The sort is in-place (i.e. the list itself is modified) and stable (i.e. the
 |      order of two equal elements is maintained).
 |      
 |      If a key function is given, apply it once to each list item and sort them,
 |      ascending or descending, according to their function values.
 |      
 |      The reverse flag can be set to sort in descending order.
 |  
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |  
 |  __class_getitem__(...) from builtins.type
 |      See PEP 585
 |  
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __hash__ = None

On peut créer facilement des listes répétitives grâce a l'opération de multiplication.

In [56]:
a = ['a', 1] * 5
print(a)
['a', 1, 'a', 1, 'a', 1, 'a', 1, 'a', 1]

Mais on ne peut pas 'diviser' une liste.

In [57]:
# Cette cellule génère une erreur
a = [1, 2, 3, 4]
print(a / 2)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[57], line 3
      1 # Cette cellule génère une erreur
      2 a = [1, 2, 3, 4]
----> 3 print(a / 2)

TypeError: unsupported operand type(s) for /: 'list' and 'int'

Exercice : Manipulez la liste L ci-dessous avec les méthodes associées aux listes.

In [58]:
L = ['egg', 'spam', 'spam', 'spam', 'bacon']
# Votre code ci-dessous

Tuples

Les Tuples (ou n-uplets en Français) sont des séquences immuables : on ne peut pas les modifier après leur création.

On les initialise ainsi :

In [59]:
T = ('a', 'b', 'c')
print(T, 'est de type', type(T))
T = 'a', 'b', 'c'  # une autre façon, en ommettant les parenthèses
print(T, 'est de type', type(T))
T = tuple(['a', 'b', 'c'])  # à partir d'une liste
print(T, 'est de type', type(T))
T = ('a')  # ceci n'est pas un tuple
print(T, 'est de type', type(T))
T = ('a',)  # Syntaxe pour initialiser un tuple contenant un seul élément
print(T, 'est de type', type(T))
# Syntaxe alternative pour initialiser u n tuple contenant un seul élément.
# Préférez celle avec parenthèses.
T = 'a',   
('a', 'b', 'c') est de type <class 'tuple'>
('a', 'b', 'c') est de type <class 'tuple'>
('a', 'b', 'c') est de type <class 'tuple'>
a est de type <class 'str'>
('a',) est de type <class 'tuple'>

Une fois créée, cette séquence ne peut être modifiée.

In [60]:
T = ('a', 'b', 'c')
print(T[1]) # On peut utiliser un élément
b
In [61]:
# Cette cellule génère une erreur
T[1] = 'z'  # mais on ne peut pas le modifier
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[61], line 2
      1 # Cette cellule génère une erreur
----> 2 T[1] = 'z'  # mais on ne peut pas le modifier

TypeError: 'tuple' object does not support item assignment

Intérêt des tuples par rapport aux listes :

  • plus rapide à parcourir que les listes
  • immuables donc "protégés"
  • peuvent être utilisés comme clé de dictionnaires (cf. plus loin)

On peut créer des tuples a partir d'autres séquences ou objets grâce à la fonction tuple().

In [62]:
a = [1, 2, 3, 'toto']
print(type(a), a)
b = tuple(a)
print(type(b), b)
a = 'azerty'
print(type(a), a)
b = tuple(a)
print(type(b), b)
<class 'list'> [1, 2, 3, 'toto']
<class 'tuple'> (1, 2, 3, 'toto')
<class 'str'> azerty
<class 'tuple'> ('a', 'z', 'e', 'r', 't', 'y')

Manipulation des tuples

Construire d'autres tuples par concaténation et multiplication

In [63]:
T1 = 'a', 'b', 'c'
print('T1 =', T1)
T2 = 'd', 'e'
print('T2 =', T2)
print('T1 + T2 =', T1 + T2)
print('T2 * 3 =', T2 * 3)
T1 = ('a', 'b', 'c')
T2 = ('d', 'e')
T1 + T2 = ('a', 'b', 'c', 'd', 'e')
T2 * 3 = ('d', 'e', 'd', 'e', 'd', 'e')

Types muables et types immuables

Avant d'aller plus loin dans la revue des types, il est important de comprendre le mécanisme d'affectation en fonction du caractère muable ou immuable de l'objet.

Cas d'un objet muable

  • Deux noms de variables différents peuvent référencer le même objet
  • Si cet objet est muable, les modifications faites par l'intermédiaire d'une des variables sont visibles par toutes les autres.
In [64]:
a = ['spam', 'egg']  # on initialise la variable a
b = a                # b référence le même objet que a

a et b possèdent la même référence :

In [65]:
print(id(a))
print(id(b))
a is b
140653681117312
140653681117312
Out[65]:
True

a et b contiennent la même donnée :

In [66]:
print(a)
print(b)
a == b
['spam', 'egg']
['spam', 'egg']
Out[66]:
True

Si on modifie la donnée de a, la donnée de b est aussi modifiée !

In [67]:
a.append('bacon')
print(a)
print(b)
['spam', 'egg', 'bacon']
['spam', 'egg', 'bacon']

Cas d'un objet immuable

In [68]:
t = 'spam', 'egg'
u = t
print(id(t))
print(id(u))
u is t
140653681117120
140653681117120
Out[68]:
True

t et u sont deux variables qui référencent le même objet tuple donc leur donnée ne peut être modifiée. Tout ce qu'on peut faire, c'est affecter une nouvelle valeur :

In [69]:
t = 'bacon', 'egg'

Dans ce cas, t référence un nouvel objet alors que u référence toujours l'objet initial :

In [70]:
print(id(t))
print(id(u))
t is u
140653681200320
140653681117120
Out[70]:
False

Et bien sûr leurs données sont différentes :

In [71]:
print(t)
print(u)
t == u
('bacon', 'egg')
('spam', 'egg')
Out[71]:
False

Exercice : analyser ce qu'il se passe dans cette série d'instructions avec Python Tutor .

Un peu plus loin...

Bien que sa séquence soit immuable, si un tuple est constitué d'éléments muables, alors ces éléments-là peuvent être modifiés.

Illustration avec un tuple dont un des éléments est une list :

In [72]:
T = ('a', ['b', 'c']) # le deuxième élément est une liste donc il est muable
print('T =', T)
L = T[1]
print('L =', L)
L[0] = 'e'
print('L =', L)
print('T =', T)
T = ('a', ['b', 'c'])
L = ['b', 'c']
L = ['e', 'c']
T = ('a', ['e', 'c'])
In [73]:
# Ici on fait exactement la même chose...
T = ('a', ['b', 'c'])
print('T =', T)
T[1][0] = 'z'
print('T après =', T)
T = ('a', ['b', 'c'])
T après = ('a', ['z', 'c'])
In [74]:
# Cette cellule génère une erreur
T[0] = 'A'  # Ici, on essaye de modifier le tuple lui même...
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[74], line 2
      1 # Cette cellule génère une erreur
----> 2 T[0] = 'A'  # Ici, on essaye de modifier le tuple lui même...

TypeError: 'tuple' object does not support item assignment

Exercice : analyser ce qu'il se passe dans cette série d'instructions avec Python Tutor .

Le slicing de séquences en Python

  • Cela consiste à extraire une sous-séquence à partir d'une séquence.
  • Le slicing fonctionne de manière similaire aux intervalles mathématiques : [début:fin[
  • La borne de fin ne fait pas partie de l'intervalle sélectionné.
  • La syntaxe générale est L[i:j:k], où :
    • i = indice de début
    • j = indice de fin, le premier élément qui n'est pas sélectionné
    • k = le "pas" ou intervalle (s'il est omis alors il vaut 1)
  • La sous-liste sera donc composée de tous les éléments de l’indice i jusqu’à l’indice j-1, par pas de k.
  • La sous-liste est un nouvel objet.

Dans le sens normal (le pas k est positif)

  • Si i est omis alors il vaut 0
  • Si j est omis alors il vaut len(L)

Dans le sens inverse (le pas k est négatif)

  • Si i est omis alors il vaut -1
  • Si j est omis alors il vaut -len(L)-1

Illustrons ça en créant une liste à partir d'une chaîne de caractères.

La fonction split() découpe une chaîne de caractères en morceaux, par défaut en 'mots'.

In [75]:
L = 'Dans le Python tout est bon'.split()
print(L)
['Dans', 'le', 'Python', 'tout', 'est', 'bon']

Pour commencer, on extrait de la liste L un nouvel objet liste qui contient tous les éléments de L <=> copie de liste

In [76]:
print(L[0:len(L):1]) # Cette notation est inutilement lourde car :
print(L[::])         # i = 0, j=len(L) et k=1 donc i, j et k peuvent être omis
print(L[:])          # on peut même ommettre le 2ème ":"
['Dans', 'le', 'Python', 'tout', 'est', 'bon']
['Dans', 'le', 'Python', 'tout', 'est', 'bon']
['Dans', 'le', 'Python', 'tout', 'est', 'bon']

On extrait une sous-liste qui ne contient que les 3 premiers éléments :

In [77]:
print(L[0:3:1])  # Notation complète
print(L[:3:1])  # Le premier indice vaut i=0, donc on peut l'omettre
print(L[:3])  # Le pas de slicing vaut 1, donc on peut l'omettre, ainsi que le ":" 
['Dans', 'le', 'Python']
['Dans', 'le', 'Python']
['Dans', 'le', 'Python']

J'extrais une sous-liste qui exclut les trois premiers éléments :

In [78]:
print(L[3:len(L):1])  # Cette notation est inutilement lourde car :
print(L[3:])          # j et k peuvent être omis, ainsi que le ":"
['tout', 'est', 'bon']
['tout', 'est', 'bon']

Les indices peuvent être négatifs, ce qui permet traiter les derniers éléments :

In [79]:
# Je veux exclure le dernier élément :
print(L[0:-1:1])  # Notation complète
print(L[:-1:1])  # Le premier indice vaut i=0, donc on peut l'omettre
print(L[:-1])  # Le pas de slicing vaut 1, donc on peut l'omettre
['Dans', 'le', 'Python', 'tout', 'est']
['Dans', 'le', 'Python', 'tout', 'est']
['Dans', 'le', 'Python', 'tout', 'est']

On ne garde que les deux derniers éléments

In [80]:
print(L[-2:])
['est', 'bon']

Note

L[1] n'est pas équivalent à L[1:2], ni à L[1:], ni à L[:1].

Illustration :

In [81]:
a = L[1]
print(type(a), a) # Je récupère le deuxième élément de la liste
a = L[1:2]
print(type(a), a) # Je récupère une liste composée du seul élément L[1]
a = L[1:]
print(type(a), a) # Je récupère une liste
a = L[:1]
print(type(a), a) # Je récupère une liste
<class 'str'> le
<class 'list'> ['le']
<class 'list'> ['le', 'Python', 'tout', 'est', 'bon']
<class 'list'> ['Dans']

Exercice : Retourner une liste composée des éléments de L en ordre inverse avec une opération de slicing. Toute utilisation de [].reverse() ou reversed() est interdite.

In [82]:
L[::-1]
Out[82]:
['bon', 'est', 'tout', 'Python', 'le', 'Dans']
In [83]:
# Solution

L = "Dans le Python, tout est bon.".split()

# La solution simple et élégante :
print(L[::-1])

# Explications:
# Pas de bornes => valeurs par défaut => on prend tout
# Le pas est de -1 => à l'envers

# La version explicite :
print(L[-1:-len(L)-1:-1])

# Explications :
# On commence à la dernière place
# On s'arrête à la première, exprimée en indices négatifs
# Le pas est de -1 => à l'envers

# Ne pas oublier que les indices vont:
# dans le sens normal : de 0 à 5
# dans le sens contraire : de -1 à -6

# Ne pas oublier que les bornes d'un slice qui prend tout les éléments vont:
# dans le sens normal : de 0 à 6
# dans le sens contraire : de -1 à -7

# La solution "optimale" : elle utilise un iterateur et donc
# ne consomme aucune ressource tant qu'on ne l'utilise pas
print(list(reversed(L)))

# Pour le fun, voici une version fonctionelle récursive
def rev(alist):
    if not alist:
        return []
    return alist[-1:] + rev(alist[:-1])

print(rev(L))
['bon.', 'est', 'tout', 'Python,', 'le', 'Dans']
['bon.', 'est', 'tout', 'Python,', 'le', 'Dans']
['bon.', 'est', 'tout', 'Python,', 'le', 'Dans']
['bon.', 'est', 'tout', 'Python,', 'le', 'Dans']

Le slicing peut être utilisé pour modifier une séquence muable grâce à l'opération d'affectation.

In [84]:
L = 'Dans le Python tout est bon'.split()
print(L)
L[2:4] = ['nouvelles', 'valeurs', 'et encore plus...', 1, 2, 3]
print(L) 
['Dans', 'le', 'Python', 'tout', 'est', 'bon']
['Dans', 'le', 'nouvelles', 'valeurs', 'et encore plus...', 1, 2, 3, 'est', 'bon']

Le slicing peut être utilisé sur des chaînes de caractères.

In [85]:
alphabet = 'abcdefghijklmnopqrstuvwxyz'

Exercice :

  1. Découpez l'alphabet en deux parties égales
  2. Prenez une lettre sur deux
In [86]:
# Votre code ici
milieu = len(alphabet) // 2
print(alphabet[:milieu])
print(alphabet[milieu:])
print(alphabet[::2])
abcdefghijklm
nopqrstuvwxyz
acegikmoqsuwy
In [87]:
# Solution
alphabet = "abcdefghijklmnopqrstuvwxyz"

# 1.
milieu = len(alphabet) // 2
print(alphabet[:milieu])
print(alphabet[milieu:])

# 2.
print(alphabet[::2])
abcdefghijklm
nopqrstuvwxyz
acegikmoqsuwy

Chaînes de caractères, le retour

Les chaînes de caractères sont des séquences immuables donc on les manipule comme telles.

In [88]:
# Cette cellule génère une erreur
immuable = 'abcdefgh'
immuable[3] = 'D'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[88], line 3
      1 # Cette cellule génère une erreur
      2 immuable = 'abcdefgh'
----> 3 immuable[3] = 'D'

TypeError: 'str' object does not support item assignment

Il faut construire une nouvelle chaîne de caractère. En concaténant des morceaux (slices) de la chaîne originale:

In [89]:
nouvelle_chaine = immuable[:3] + 'D' + immuable[4:]
print(nouvelle_chaine)
abcDefgh

Ou alors en utilisant une transformation en liste, puis à nouveau en chaîne:

In [90]:
a = list(immuable)
print(a)
a[3] = 'D'
print(a)
print(''.join(a))
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
['a', 'b', 'c', 'D', 'e', 'f', 'g', 'h']
abcDefgh

On peut savoir si une chaîne se trouve dans une autre

In [91]:
print('123' in 'azerty_123_uiop')
print('AZE' in 'azerty_123_uiop')
print('aze' in 'azerty_123_uiop')
True
False
True

La longueur d'une chaîne s'obtient avec len().

In [92]:
print(len(immuable))
8

Exercice, dans la cellule ci-dessous:

  1. Insérez le caractère # au milieu de la chaîne donnée.
  2. Idem mais coupez la chaine en 3 parties, et insérez le caractère @ entre chacune d'elles.
  3. Insérez le caractère | entre chaque caractère de la chaîne.
In [93]:
chaine_donnee = 'azertyuioppoiuytreza'
# Votre code ici
In [94]:
# Solution
chaine_donnee = "azertyuioppoiuytreza"

milieu = len(chaine_donnee) // 2
print(chaine_donnee[:milieu] + '#' + chaine_donnee[milieu:])

intervale = len(chaine_donnee) // 3
print(chaine_donnee[:intervale] + '@' + chaine_donnee[intervale:2 * intervale + 1] + '@' + chaine_donnee[2 * intervale + 1:])

print('|'.join(chaine_donnee))
azertyuiop#poiuytreza
azerty@uioppoi@uytreza
a|z|e|r|t|y|u|i|o|p|p|o|i|u|y|t|r|e|z|a

Les dictionnaires

Les dictionnaires ou listes associatives sont des conteneurs où les objets ne sont pas ordonnés ni accessibles par un indice mais sont associés à une clé d'accès.

L'accès aux éléments se fait comme pour les listes ou tuples, avec les [].

dico = {cle1: valeur1, cle2: valeur2, ...}

Les clés peuvent avoir n'importe qu'elle valeur à condition qu'elles soient de type immuable : les listes ne peuvent pas servir de clés alors que les chaînes de caractères et les tuples le peuvent.

Dans dico, on accède à valeur1 avec la syntaxe dico[cle1].

Un exemple

In [95]:
dic_animaux = {'ane': True, 'arbre': False, 'chat': True, 'lune': False, 'humain': True}
cle = 'chat'
valeur = dic_animaux[cle]
print(valeur)
print('{} est un animal: {}'.format(cle, valeur))
# Ou encore
print('{} est un animal: {}'.format('chat', dic_animaux['chat']))
# En utilisant les f-strings :
print(f"{'chat'} est un animal: {dic_animaux['chat']}")
True
chat est un animal: True
chat est un animal: True
chat est un animal: True

Exercice : essayez de savoir si un arbre est un animal

In [96]:
# Votre code ici
In [97]:
# Solution
print("l'arbre est un animal:", dic_animaux['arbre'])
l'arbre est un animal: False

Les différentes manières de créer des dictionnaires, en particulier grâce à la fonction interne dict() :

In [98]:
a = {'un': 1, 'deux': 2, 'trois': 3}               # Les accolades comme syntaxe
b = dict(un=1, deux=2, trois=3)                    # La méthode dict()
c = dict(zip(['un', 'deux', 'trois'], [1, 2, 3]))  # On "zippe" deux listes
d = dict([('deux', 2), ('un', 1), ('trois', 3)])   # On transforme une liste de 2-tuples
e = dict({'trois': 3, 'un': 1, 'deux': 2})
a == b == c == d == e
Out[98]:
True

Accéder à un élément qui n'est pas dans le dictionnaire génère une erreur. Il existe la méthode {}.get() ou l'opérateur in qui permettent d'éviter ce problème.

In [99]:
# Cette cellule génère une erreur
err = a['quatre']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[99], line 2
      1 # Cette cellule génère une erreur
----> 2 err = a['quatre']

KeyError: 'quatre'

Ici on utilise .get() et cela ne remonte pas d'erreur.

In [100]:
print(a.get('quatre'))    # La valeur par défaut est 'None' lorsque .get() ne trouve pas l'élément
print(a.get('quatre', 5)) # On peut spécifier une autre valeur par défaut
None
5

Un autre exemple

In [101]:
tup_mois = ('jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec')
tup_long = (31, (28, 29), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
dic_mois = dict(zip(tup_mois, tup_long))
mois_naissance = 'jul'
print(f'Il y a {dic_mois[mois_naissance]:d} jours dans votre mois de naissance')
Il y a 31 jours dans votre mois de naissance

Exercice:

  1. Modifiez la cellule précédente pour y changer mois_naissance (les 3 premiers caractères de votre mois de naissance, en anglais). Ré-exécutez la cellule et vérifiez la réponse.
  2. Un problème s'est glissé dans la cellule, lequel ?
  3. Corrigez-le (il y a plusieurs manières de faire).

Les dictionnaires sont muables.

In [102]:
ages = {'albert': 62, 'bob': 34, 'charlie': 1, 'daphne': 67}
print(ages)
print(f'Albert a {ages["albert"]} ans.')
# C'est l'anniversaire de charlie, il a un an de plus...
ages['charlie'] += 1  # equivalent à : ages['charlie'] = ages['charlie'] + 1
print(ages)
# Bob est parti, enlevons-le
del ages['bob']
print(ages)
{'albert': 62, 'bob': 34, 'charlie': 1, 'daphne': 67}
Albert a 62 ans.
{'albert': 62, 'bob': 34, 'charlie': 2, 'daphne': 67}
{'albert': 62, 'charlie': 2, 'daphne': 67}
  • Savoir si une clé est présente dans un dictionnaire est une opération rapide. On utilise, comme pour les séquences, l'opérateur in.
  • La fonction interne len() est utilisable pour savoir combien d'objets sont référencés dans le dictionnaire.
In [103]:
ages = {'albert': 62, 'bob': 34, 'charlie': 1, 'daphne': 67}
print('Charlie est dedans ?', 'charlie' in ages)
print('Zoé est dedans ?', 'zoé' in ages)
print('Bob est dedans ?', 'bob' in ages)
print(f'Il y a {len(ages):d} personnes.')
# Bob est parti, enlevons-le
del ages['bob']
print('Bob est dedans ?', 'bob' in ages)
print(f'Il y a {len(ages):d} personnes.')
Charlie est dedans ? True
Zoé est dedans ? False
Bob est dedans ? True
Il y a 4 personnes.
Bob est dedans ? False
Il y a 3 personnes.

On peut itérer sur les clés ou les objets référencés, ou vider un dictionnaire, en comparer deux, etc.

Pour plus d'informations sur les dictionnaires, voir ici.

Exercice :

  1. Créez un dictionnaire qui va traduire des chiffres (de 1 à 3) écrits en toutes lettres entre deux langues. Par exemple : trad_num['un'] $\rightarrow$ 'one'
  2. Modifiez ce dictionnaire, pour qu'il fonctionne dans les deux sens de traduction (Fr $\rightarrow$ En et En $\rightarrow$ Fr)
  3. Modifiez ce dictionnaire, pour qu'il fonctionne aussi avec les chiffres sous forme d'entiers. Par exemple : trad_num[1] $\rightarrow$ 'un'
In [104]:
# Votre code ici
In [105]:
# -- une première solution --

# Des tuples
fr = 'un', 'deux', 'trois'
en = 'one', 'two', 'three'
num = 1, 2, 3

# Des dictionnaires
trad_fr_en = dict(zip(fr, en))
trad_en_fr = dict(zip(en, fr))
trad___num = dict(zip(num, fr))

# Le dico qui fait rien
trad = {}

# Maintenant il peut tout faire
trad.update(trad_fr_en)
trad.update(trad_en_fr)
trad.update(trad___num)

# La preuve
print("'un' \t devient:", trad['un'])
print("'two' \t devient:", trad['two'])
print("3 \t devient:", trad[3])

print('trad:', trad)
# -- une solution concise --

trad_num = {'un': 'one', 'deux': 'two', 'trois': 'three'}
print(trad_num['deux'])  # On teste Fr -> En
trad_num.update({valeur: cle for cle, valeur in trad_num.items()})
print(trad_num)
'un' 	 devient: one
'two' 	 devient: deux
3 	 devient: trois
trad: {'un': 'one', 'deux': 'two', 'trois': 'three', 'one': 'un', 'two': 'deux', 'three': 'trois', 1: 'un', 2: 'deux', 3: 'trois'}
two
{'un': 'one', 'deux': 'two', 'trois': 'three', 'one': 'un', 'two': 'deux', 'three': 'trois'}

Les ensembles

La fonction set() permet de créer des ensembles. Les ensembles sont des conteneurs qui n'autorisent pas de duplication d'objets référencés, contrairement aux listes et tuples.

On peut créer des ensembles de cette façon :

ensemble = set(iterable)

iterable peut être n'importe quel objet qui supporte l'itération : liste, tuple, dictionnaire, un autre set (pour en faire une copie), vos propres objets itérables, etc...

Tout comme pour les dictionnaires, l'opérateur in est efficace.

Exemples

In [106]:
tupl1 = ('un', 'un', 'deux', 1, 3)
list1 = [1, 1, 2]

a = set(tupl1)
b = set(list1)

print(a, b)

print("La chaîne 'un' est elle dans l'ensemble ?", 'un' in a)
a.remove('un')
print("La chaîne 'un' est-elle toujours dans l'ensemble ?", 'un' in a)

print(a, b)
{3, 'deux', 'un', 1} {1, 2}
La chaîne 'un' est elle dans l'ensemble ? True
La chaîne 'un' est-elle toujours dans l'ensemble ? False
{3, 'deux', 1} {1, 2}

Des opérations supplémentaires sont possibles sur des ensembles. Elles sont calquées sur les opérations mathématiques :

  • union
  • intersection
  • etc...
In [107]:
print('intersection :', a & b)
print('union :', a | b)
intersection : {1}
union : {'deux', 1, 3, 2}

Pour plus d'informations sur les ensembles, voir ici

Fichiers

Ouverture

L'instruction :

f = open('interessant.txt', mode='r')

ouvre le fichier interessant.txt en mode lecture seule et le renvoie dans l'objet f.

  • On peut spécifier un chemin d'accès complet ou relatif au répertoire courant
  • Le caractère de séparation pour les répertoires peut être différent en fonction du système d'exploitation (/ pour unix et \ pour windows), voir le module os.path ou mieux la bibliothèque pathlib.

Modes d'ouverture communs

  • 'r' : lecture seule
  • 'w' : écriture seule
  • 'a' : ajout à partir de la fin du fichier

Note : Avec 'w' et 'a', le fichier est créé s'il n'existe pas.

Pour plus d'informations sur les objets fichiers, voir ici, pour la documentation de la fonction open(), voir .

Fermeture

On ferme le fichier f avec l'instruction :

f.close()

Méthodes de lecture

  • f.read() : retourne tout le contenu de f sous la forme d’une chaîne de caractères.
In [108]:
f = open('exos/interessant.txt', mode='r')
texte = f.read()
f.close()
print(f'"texte" est un objet de type {type(texte)} de longueur {len(texte)} caractères:')
print(texte)
print('Contenu en raw string:')
print(repr(texte))
%pycat exos/interessant.txt
"texte" est un objet de type <class 'str'> de longueur 74 caractères:
Si vous lisez ce texte alors
...
vous savez lire un fichier avec Python !

Contenu en raw string:
'Si vous lisez ce texte alors\n...\nvous savez lire un fichier avec Python !\n'
  • f.readlines() : retourne toutes les lignes de f sous la forme d’une liste de chaînes de caractères.
In [109]:
f = open('exos/interessant.txt', mode='r')
lignes = f.readlines()
f.close() 
print(f'"lignes" est un objet de type {type(lignes)} contenant {len(lignes)} éléments:')
print(lignes)
"lignes" est un objet de type <class 'list'> contenant 3 éléments:
['Si vous lisez ce texte alors\n', '...\n', 'vous savez lire un fichier avec Python !\n']

Méthodes d'écriture

  • f.write('du texte') : écrit la chaine 'du texte' dans f
In [110]:
chaine = 'Je sais écrire\n...\navec Python !\n'
# mode 'w' : on écrase le contenu du fichier s'il existe
f = open('pas_mal.txt', mode='w', encoding='utf-8')
f.write(chaine)
f.close() 
%pycat pas_mal.txt

Note : du point de vue du système, rien n'est écrit dans le fichier avant l’appel de f.close()

  • f.writelines(ma_sequence) : écrit la séquence ma_sequence dans f en mettant bout à bout les éléments
In [111]:
sequence = ['Je sais ajouter\n', 'du texte\n', 'avec Python !\n']
f = open('pas_mal.txt', mode='a')
# mode 'a' : on ajoute à la fin du fichier
f.writelines(sequence)
f.close()
%pycat pas_mal.txt

Exercice :

  1. écrire le contenu de la liste mystere dans le fichier coded.txt puis fermer ce dernier
  2. lire le fichier coded.txt et le stocker dans une chaine coded
  3. Décoder la chaîne coded avec les instructions suivantes:
import codecs
decoded = codecs.decode(coded, encoding='rot13')
  1. écrire la chaine decoded dans le fichier decoded.txt et fermer ce dernier
  2. visualiser le contenu du fichier decoded.txt dans un éditeur de texte
In [112]:
mystere = ['Gur Mra bs Clguba, ol Gvz Crgref\n\n',
           'Ornhgvshy vf orggre guna htyl.\n',
           'Rkcyvpvg vf orggre guna vzcyvpvg.\n']
# Votre code ci-dessous
In [113]:
# Solution
mystere = ["Gur Mra bs Clguba, ol Gvz Crgref\n\n",
           "Ornhgvshy vf orggre guna htyl.\n",
           "Rkcyvpvg vf orggre guna vzcyvpvg.\n"]

# 1. On écrit ces chaînes de caractères dans le fichier "coded.txt"
f = open('coded.txt', mode='w')
f.writelines(mystere)
f.close()

# 2. On relit le contenu du fichier "coded.txt" que l'on vient de créer
f = open('coded.txt', mode='r')
coded = f.read()
f.close()

# 3. On décode le message mystérieux
# Cette ligne permet l'utilisation de codecs.decode(), c.f. ligne 21
import codecs
decoded = codecs.decode(coded, encoding='rot13')

# 4. On écrit le message décodé dans un autre fichier
f = open('decoded.txt', mode='w')
f.write(decoded)
f.close()

# 5. On consulte le contenu du message décodé dans le fichier "decoded.txt"
%pycat decoded.txt