|
@@ -1,184 +1,225 @@ |
|
|
% Programmation avec Python (chapitre 3) |
|
|
% Programmation avec Python (chapitre 3) |
|
|
% Dimitri Merejkowsky |
|
|
% Dimitri Merejkowsky |
|
|
|
|
|
|
|
|
\centering |
|
|
|
|
|
Retours sur le chapitre 2 |
|
|
|
|
|
|
|
|
|
|
|
# |
|
|
|
|
|
|
|
|
|
|
|
\centering |
|
|
|
|
|
Retour sur les listes |
|
|
|
|
|
|
|
|
\center \huge None |
|
|
|
|
|
|
|
|
# extend() |
|
|
|
|
|
|
|
|
# Exprimer l'absence |
|
|
|
|
|
|
|
|
Pour concaténer des listes: |
|
|
|
|
|
|
|
|
Exemple: clé non présente dans un dictionnaire: |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> fruits = ["pomme", "banane"] |
|
|
|
|
|
>>> fruits.extend(["orange", "abricot"]) |
|
|
|
|
|
>>> fruits |
|
|
|
|
|
['pomme', 'banane', 'orange', 'abricot'] |
|
|
|
|
|
|
|
|
>>> scores = { "Anne": 42, "Bernard": 5 } |
|
|
|
|
|
>>> score1 = scores.get("Anne") |
|
|
|
|
|
>>> score1 |
|
|
|
|
|
42 |
|
|
|
|
|
>>> score2 = scores.get("Sophie") |
|
|
|
|
|
>>> score2 |
|
|
|
|
|
<rien> |
|
|
``` |
|
|
``` |
|
|
\vfill |
|
|
|
|
|
|
|
|
|
|
|
Peut aussi s'écrire `+=` |
|
|
|
|
|
|
|
|
En réalité, `score2` a bien une valeur: `None`. |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
>>> nombres = [1, 2] |
|
|
|
|
|
>>> nombres += [3, 4] |
|
|
|
|
|
>>> nombres |
|
|
|
|
|
[1, 2, 3, 4] |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
L'interpréteur n'affiche rien quand la valeur est `None` |
|
|
|
|
|
|
|
|
# pop() |
|
|
|
|
|
|
|
|
|
|
|
`pop()` existe aussi pour les listes: |
|
|
|
|
|
|
|
|
# None est ambigu |
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
None est `falsy`, tout comme 0, False et les listes vides: |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> fruits = ["pomme", "banane"] |
|
|
|
|
|
>>> fruits.pop() # Retourne l'élément |
|
|
|
|
|
'pomme' |
|
|
|
|
|
>>> fruits # Et modifie la liste |
|
|
|
|
|
["banane"] |
|
|
|
|
|
|
|
|
|
|
|
>>> vide = list() |
|
|
|
|
|
>>> vide.pop() |
|
|
|
|
|
IndexError |
|
|
|
|
|
|
|
|
element = dictionnaire.get(clé) |
|
|
|
|
|
if not element: |
|
|
|
|
|
... |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# clear() |
|
|
|
|
|
|
|
|
Mais ici, comment faire la différence entre: |
|
|
|
|
|
|
|
|
Pour vider une liste: |
|
|
|
|
|
|
|
|
* la clé existe et vaut None |
|
|
|
|
|
* la clé existe et est falsy |
|
|
|
|
|
* la clé n'existe pas ? |
|
|
|
|
|
|
|
|
|
|
|
# Solution 1: tester l'appartenance |
|
|
|
|
|
|
|
|
|
|
|
Avec `in`: |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> fruits = ["pomme", "banane"] |
|
|
|
|
|
>>> fruits.clear() |
|
|
|
|
|
>>> fruits |
|
|
|
|
|
[] |
|
|
|
|
|
|
|
|
if clé in dictionnaire: |
|
|
|
|
|
# La clé existe, pas d'erreur |
|
|
|
|
|
valeur = dictionnaire[clé] |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# index() |
|
|
|
|
|
|
|
|
# Solution 2: tester None |
|
|
|
|
|
|
|
|
Pour récupérer la position d'un élément: |
|
|
|
|
|
|
|
|
Avec `is`: |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> fruits = ["pomme", "banane"] |
|
|
|
|
|
>>> fruits.index("banane") |
|
|
|
|
|
>>> 1 |
|
|
|
|
|
>>> fruits.index("citron") |
|
|
|
|
|
>> ValueError |
|
|
|
|
|
|
|
|
>>> scores = { "Anne": 42, "Bernard": 5 } |
|
|
|
|
|
>>> score1 = scores.get("Anne") |
|
|
|
|
|
>>> score1 is None |
|
|
|
|
|
False |
|
|
|
|
|
>>> score2 = scores.get("Sophie") |
|
|
|
|
|
>>> score2 is None |
|
|
|
|
|
True |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# count() |
|
|
|
|
|
|
|
|
|
|
|
Pour compter le nombre d'occurrences d'un élément |
|
|
|
|
|
|
|
|
# Retourner None |
|
|
|
|
|
|
|
|
|
|
|
`None` est aussi la valeur par défaut lorsqu'il n'y a pas de `return` |
|
|
|
|
|
dans le corps de la fonction: |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> fruits = ["pomme", "banane", "pomme", "poire"] |
|
|
|
|
|
>>> fruits.count("pomme") |
|
|
|
|
|
2 |
|
|
|
|
|
>>> fruits.count("poire") |
|
|
|
|
|
1 |
|
|
|
|
|
>>> fruits.count("citron") |
|
|
|
|
|
0 |
|
|
|
|
|
|
|
|
>>> def ne_retourne_rien(a, b): |
|
|
|
|
|
>>> c = a + b |
|
|
|
|
|
|
|
|
|
|
|
>>> résultat = ne_retourne_rien(3, 2) |
|
|
|
|
|
>>> résultat is None |
|
|
|
|
|
True |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
# Retourner None (2) |
|
|
|
|
|
|
|
|
|
|
|
On dit aussi que la fonction est une *procédure*. |
|
|
|
|
|
|
|
|
|
|
|
On a déjà écrit des procédures: dans `pendu.py`, `display_hint()` et `main()` |
|
|
|
|
|
ne retournaient rien. |
|
|
|
|
|
|
|
|
# sort() |
|
|
|
|
|
|
|
|
# Retourner None au autre chose |
|
|
|
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
def trouve_dans_liste1(liste, element): |
|
|
|
|
|
if element in list: |
|
|
|
|
|
return liste.index(element) |
|
|
|
|
|
|
|
|
Pour trier une liste. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def trouve_dans_liste2(liste, element): |
|
|
|
|
|
if element in list: |
|
|
|
|
|
return liste.index(element) |
|
|
|
|
|
else: |
|
|
|
|
|
return None |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
\vfill |
|
|
\vfill |
|
|
|
|
|
|
|
|
* Par ordre naturel |
|
|
|
|
|
|
|
|
Les deux fonctions font la même chose : `trouve_dans_liste2` est simplement plus *explicite.* |
|
|
|
|
|
|
|
|
|
|
|
# Types optionnels |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> nombres = [2, 3, 1, 5] |
|
|
|
|
|
>>> nombres.sort() |
|
|
|
|
|
>>> nombres |
|
|
|
|
|
[1, 2, 3, 5] |
|
|
|
|
|
|
|
|
def trouve_dans_liste(liste, element): |
|
|
|
|
|
if element in list: |
|
|
|
|
|
return liste.index(element) |
|
|
|
|
|
else: |
|
|
|
|
|
return None |
|
|
``` |
|
|
``` |
|
|
|
|
|
On dit aussi que le type de retour de `trouve_dans_liste` est *optionnel*. |
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
# |
|
|
|
|
|
|
|
|
|
|
|
\centering \huge Retour sur les listes |
|
|
|
|
|
|
|
|
* Par ordre alphabétique |
|
|
|
|
|
|
|
|
# Méthodes |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> mots = ["abeille", "faucon", "chat"] |
|
|
|
|
|
>>> mots.sort() |
|
|
|
|
|
['abeille', 'chat', 'faucon'] |
|
|
|
|
|
|
|
|
fruits = ["pomme", "banane"] |
|
|
|
|
|
fruits.append("orange") |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# Ordre lexicographique |
|
|
|
|
|
|
|
|
Quand on écrit `fruits.append("orange")`, on peut voir `append()` |
|
|
|
|
|
comme une "fonction" qui prendrait `fruits` en argument implicite |
|
|
|
|
|
(avant le `.`), et `orange` en argument explicite. |
|
|
|
|
|
|
|
|
Pour chaque "liste-élément" on compare le premier élément. |
|
|
|
|
|
S'il y a égalité, on regarde le deuxième élément, etc: |
|
|
|
|
|
|
|
|
On appelle ce genre de fonction une **méthode**. |
|
|
|
|
|
|
|
|
|
|
|
# clear() |
|
|
|
|
|
|
|
|
|
|
|
Pour vider une liste: |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> composite = [["chat", 1], ["abeille", 2], ["chat", 3]] |
|
|
|
|
|
>>> composite.sort() |
|
|
|
|
|
[['abeille', 2], ['chat', 1], ['chat', 3]] |
|
|
|
|
|
|
|
|
>>> fruits = ["pomme", "banane"] |
|
|
|
|
|
>>> fruits.clear() |
|
|
|
|
|
>>> fruits |
|
|
|
|
|
[] |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
Notez que la méthode `clear()` ne renvoie rien! |
|
|
|
|
|
La liste est modifiée *sur place*. |
|
|
|
|
|
|
|
|
L'ordre alphabétique est l'ordre lexicographique pour les chaînes de caractères :) |
|
|
|
|
|
|
|
|
|
|
|
# Attention! |
|
|
|
|
|
|
|
|
# extend() |
|
|
|
|
|
|
|
|
|
|
|
Pour concaténer des listes: |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> mauvaise_liste = ["un", 2] |
|
|
|
|
|
>>> mauvaise_liste.sort() |
|
|
|
|
|
TypeError |
|
|
|
|
|
|
|
|
>>> fruits = ["pomme", "banane"] |
|
|
|
|
|
>>> fruits.extend(["orange", "abricot"]) |
|
|
|
|
|
>>> fruits |
|
|
|
|
|
['pomme', 'banane', 'orange', 'abricot'] |
|
|
``` |
|
|
``` |
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
|
|
|
Peut aussi s'écrire `+=` |
|
|
|
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
>>> nombres = [1, 2] |
|
|
|
|
|
>>> nombres += [3, 4] |
|
|
|
|
|
>>> nombres |
|
|
|
|
|
[1, 2, 3, 4] |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
# Comparer autrement |
|
|
|
|
|
|
|
|
|
|
|
Trier les mots par leur taille |
|
|
|
|
|
|
|
|
# pop() |
|
|
|
|
|
|
|
|
* Avec l'argument `key` |
|
|
|
|
|
|
|
|
On a vu la méthode `pop()` pour les dictionnaires, mais elle existe |
|
|
|
|
|
aussi pour les listes: |
|
|
|
|
|
|
|
|
\vfill |
|
|
\vfill |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
def taille(mot): |
|
|
|
|
|
return len(mot) |
|
|
|
|
|
|
|
|
>>> fruits = ["pomme", "banane"] |
|
|
|
|
|
>>> fruits.pop() # Retourne l'élément |
|
|
|
|
|
'pomme' |
|
|
|
|
|
>>> fruits # Et modifie la liste |
|
|
|
|
|
["banane"] |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
mots = ["chat", "abeille", "faucon"] |
|
|
|
|
|
mots.sort(key=taille) |
|
|
|
|
|
>>> mots |
|
|
|
|
|
["chat", "faucon", "abeille"] |
|
|
|
|
|
|
|
|
# pop() sur liste vide |
|
|
|
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
>>> liste_vide = list() |
|
|
|
|
|
>>> liste_vide.pop() |
|
|
|
|
|
IndexError |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# Lambda |
|
|
|
|
|
|
|
|
|
|
|
Sert définir une fonction sans utiliser `def` |
|
|
|
|
|
|
|
|
# index() |
|
|
|
|
|
|
|
|
|
|
|
Pour récupérer la position d'un élément: |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> retourne_42 = lambda: 42 # pas d'argument |
|
|
|
|
|
>>> retourne_42() |
|
|
|
|
|
42 |
|
|
|
|
|
>>> ajoute_deux = lambda x: x + 2 # un seul argument |
|
|
|
|
|
>>> ajoute_deux(3) |
|
|
|
|
|
5 |
|
|
|
|
|
>>> multiplie = lambda x, y: x* y # deux arguments |
|
|
|
|
|
>>> multiplie(2, 3) |
|
|
|
|
|
6 |
|
|
|
|
|
|
|
|
>>> fruits = ["pomme", "banane"] |
|
|
|
|
|
>>> fruits.index("banane") |
|
|
|
|
|
>>> 1 |
|
|
|
|
|
>>> fruits.index("citron") |
|
|
|
|
|
>> ValueError |
|
|
``` |
|
|
``` |
|
|
Note: le corps de la fonction doit tenir en une seule ligne |
|
|
|
|
|
|
|
|
|
|
|
# Utilisation avec sort |
|
|
|
|
|
|
|
|
# count() |
|
|
|
|
|
|
|
|
|
|
|
Pour compter le nombre d'occurrences d'un élément |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> mots = ["chat", "abeille", "faucon"] |
|
|
|
|
|
>>> mots.sort(key=lambda x: len(x)) |
|
|
|
|
|
>>> mots |
|
|
|
|
|
["chat", "faucon", "abeille"] |
|
|
|
|
|
|
|
|
>>> fruits = ["pomme", "banane", "pomme", "poire"] |
|
|
|
|
|
>>> fruits.count("pomme") |
|
|
|
|
|
2 |
|
|
|
|
|
>>> fruits.count("poire") |
|
|
|
|
|
1 |
|
|
|
|
|
>>> fruits.count("citron") |
|
|
|
|
|
0 |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Indexer des listes |
|
|
# Indexer des listes |
|
|
|
|
|
|
|
|
Rappel: |
|
|
Rappel: |
|
@@ -214,14 +255,19 @@ Ou "faire des slices", ou "slicer". |
|
|
['d', 'e'] |
|
|
['d', 'e'] |
|
|
>>> lettres[1:-2] # fin négative |
|
|
>>> lettres[1:-2] # fin négative |
|
|
['b', 'c'] |
|
|
['b', 'c'] |
|
|
>>> lettres[:] # une copie |
|
|
|
|
|
['a', 'b', 'c', 'd', 'e'] |
|
|
|
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# |
|
|
# |
|
|
|
|
|
|
|
|
\centering |
|
|
|
|
|
Retour sur les strings |
|
|
|
|
|
|
|
|
\centering \huge Retour sur les strings |
|
|
|
|
|
|
|
|
|
|
|
# Rappel |
|
|
|
|
|
|
|
|
|
|
|
On a vu que les strings étaient "presque" des liste de caractères. |
|
|
|
|
|
|
|
|
|
|
|
Par exemple, on peut itérer sur les lettres d'un mot avec: `for lettre |
|
|
|
|
|
in mot`. |
|
|
|
|
|
|
|
|
# index() et count() marchent aussi |
|
|
# index() et count() marchent aussi |
|
|
|
|
|
|
|
@@ -235,7 +281,7 @@ Retour sur les strings |
|
|
|
|
|
|
|
|
# Trancher des chaînes de caractères |
|
|
# Trancher des chaînes de caractères |
|
|
|
|
|
|
|
|
Ou slicer des strings: |
|
|
|
|
|
|
|
|
On peu aussi slicer des strings: |
|
|
|
|
|
|
|
|
\vfill |
|
|
\vfill |
|
|
|
|
|
|
|
@@ -249,290 +295,359 @@ Ou slicer des strings: |
|
|
'monde' |
|
|
'monde' |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
# Les strings sont immuables |
|
|
|
|
|
|
|
|
# Formater des chaînes de caractères |
|
|
|
|
|
|
|
|
Mais on ne **peut pas** modifier une string "sur place". |
|
|
|
|
|
|
|
|
Problème: |
|
|
|
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
>>> message = "Bonjour, monde !" |
|
|
|
|
|
>>> message[-1] = "?" |
|
|
|
|
|
TypeError |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> nom = "Ford" |
|
|
|
|
|
>>> résultat = 42 |
|
|
|
|
|
>>> message = "Bonjour, " + nom + ". " |
|
|
|
|
|
>>> message += "La réponse est: " + str(résultat) + "." |
|
|
|
|
|
>>> message |
|
|
|
|
|
'Bonjour, Ford. La réponse est: 42.' |
|
|
|
|
|
|
|
|
>>> message = "Bonjour, monde !" |
|
|
|
|
|
>>> message.clear() |
|
|
|
|
|
AttributeError |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
# |
|
|
|
|
|
|
|
|
Ce n'est pas très lisible! |
|
|
|
|
|
|
|
|
\centering \huge La ligne de commande |
|
|
|
|
|
|
|
|
# format() |
|
|
|
|
|
|
|
|
# Schéma |
|
|
|
|
|
|
|
|
Solution: utiliser un "template" et la méthode `format()` |
|
|
|
|
|
|
|
|
![programme](programme.png) |
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
# Entrée / sortie |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
>>> nom = "Ford" |
|
|
|
|
|
>>> résultat = 42 |
|
|
|
|
|
>>> template = "Bonjour, {}. La réponse est: {}" |
|
|
|
|
|
>>> message = template.format(nom, résultat) |
|
|
|
|
|
>>> message |
|
|
|
|
|
'Bonjour, Ford. La réponse est: 42.' |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
3 canaux: |
|
|
|
|
|
|
|
|
# format() avancé |
|
|
|
|
|
|
|
|
* Une entrée qu'on peut lire (`stdin`) |
|
|
|
|
|
* Deux sorties: |
|
|
|
|
|
* Sortie normale (ou standard) (`stdout`) |
|
|
|
|
|
* Sortie d'erreur (`stdout`) |
|
|
|
|
|
|
|
|
On peut aussi nommer les remplacements: |
|
|
|
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
template = "Bonjour, {nom}. La réponse est: {résultat}" |
|
|
|
|
|
template.format(nom="Ford", résultat=42) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
# Accès en Python |
|
|
|
|
|
|
|
|
# format() avancé |
|
|
|
|
|
|
|
|
* Pour lire stdin: `input()` |
|
|
|
|
|
* Pour écrire dans stdout: `print()` |
|
|
|
|
|
* Pour écrire dans stderr: pas de fonction native |
|
|
|
|
|
|
|
|
On peut aussi faire des alignements et du "padding": |
|
|
|
|
|
|
|
|
# Accès en Python (2) |
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
Rajouter `import sys` en haut du fichier, puis: |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
template = "{name:>10}: {score:03}" |
|
|
|
|
|
print(template.format(name="Alice", score=42)) |
|
|
|
|
|
print(template.format(name="Bob", score=5)) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
* `sys.stdin.read()` |
|
|
|
|
|
* `sys.stout.write()` |
|
|
|
|
|
* `sys.stderr.write()` |
|
|
|
|
|
|
|
|
``` |
|
|
|
|
|
Alice: 042 |
|
|
|
|
|
Bob: 005 |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
On peut aussi utiliser: |
|
|
|
|
|
|
|
|
# Explications |
|
|
|
|
|
|
|
|
`print("erreur", file=sys.stderr)` |
|
|
|
|
|
|
|
|
Le texte dans les accolades après le `:` est un mini-langage de spécification de format: |
|
|
|
|
|
|
|
|
|
|
|
* `>10` signifie: "aligner a droite, taille maximale 10" |
|
|
|
|
|
* `03` signifie: "rajouter des zéros en début de nombre jusquà atteindre 3 chiffres". |
|
|
|
|
|
|
|
|
# Accès depuis l'invite de commande |
|
|
|
|
|
|
|
|
Plus de précisions dans la documentation: |
|
|
|
|
|
|
|
|
On dit aussi *shell*, ou *CLI* (pour *command line interface*). |
|
|
|
|
|
|
|
|
|
|
|
* stdin: Taper quand le shell vous laisse la main, finir par 'entrée' |
|
|
|
|
|
* stdout et stderr sont affichés en même temps pas défaut |
|
|
|
|
|
|
|
|
\url{https://docs.python.org/fr/3/library/string.html#format-specification-mini-language}. |
|
|
|
|
|
|
|
|
# Rediriger stdout |
|
|
|
|
|
|
|
|
# |
|
|
|
|
|
|
|
|
Linux , macOS, Windows: |
|
|
|
|
|
|
|
|
\center |
|
|
|
|
|
None |
|
|
|
|
|
|
|
|
``` |
|
|
|
|
|
python3 fichier.py > output.txt |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
# Exprimer l'absence |
|
|
|
|
|
|
|
|
stdout sera écrit dans `output.txt`, et seul `stderr` sera visible. |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
>>> scores = { "Anne": 42, "Bernard": 5 } |
|
|
|
|
|
>>> score1 = scores.get("Anne") |
|
|
|
|
|
>>> score1 |
|
|
|
|
|
42 |
|
|
|
|
|
>>> score2 = scores.get("Sophie") |
|
|
|
|
|
>>> score2 |
|
|
|
|
|
<rien> |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
En réalité, `score2` a bien une valeur: `None`. |
|
|
|
|
|
|
|
|
# Code de retour |
|
|
|
|
|
|
|
|
L'interpréteur n'affiche rien quand la valeur est `None` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* 0 quand tout va bien |
|
|
|
|
|
* un autre entier quand quelque chose va mal |
|
|
|
|
|
|
|
|
# None est falsy |
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
element = dictionnaire.get(clé) |
|
|
|
|
|
if element: |
|
|
|
|
|
... |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
> Toutes les familles heureuses se ressemblent, mais chaque famille |
|
|
|
|
|
> malheureuse l'est à sa façon. |
|
|
|
|
|
> |
|
|
|
|
|
> Tolstoï |
|
|
|
|
|
|
|
|
Mais ici, comment faire la différence entre: |
|
|
|
|
|
|
|
|
# Code de retour |
|
|
|
|
|
|
|
|
* la clé existe et vaut 0, une chaîne vide, ou quoique ce soit de falsy |
|
|
|
|
|
* la clé existe et vaut None |
|
|
|
|
|
* la clé n'existe pas |
|
|
|
|
|
|
|
|
Les valeurs d'erreur possibles sont en général présentes |
|
|
|
|
|
dans la documentation. |
|
|
|
|
|
|
|
|
# Tester l'appartenance |
|
|
|
|
|
|
|
|
Note: **ne pas retourner 0** en cas d'erreur, même minime, et même si |
|
|
|
|
|
un message a été affiché. |
|
|
|
|
|
|
|
|
Avec `in`: |
|
|
|
|
|
|
|
|
C'est important pour pourvoir composer plusieurs programmes (on y |
|
|
|
|
|
reviendra). |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
if clé in dictionnaire: |
|
|
|
|
|
# La clé existe, pas d'erreur |
|
|
|
|
|
valeur = dictionnaire[clé] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Afficher le code retour depuis le shell |
|
|
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
|
# Linux, macOS |
|
|
|
|
|
$ python3 code.py |
|
|
|
|
|
$ echo $? |
|
|
|
|
|
0 |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# Tester None |
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
|
# Windows |
|
|
|
|
|
> python3 code.py |
|
|
|
|
|
> echo %ERRORLEVEL% |
|
|
|
|
|
0 |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
Avec `is`: |
|
|
|
|
|
|
|
|
# Gestion du code de retour en Python |
|
|
|
|
|
|
|
|
|
|
|
Par défaut, le code de retour est 0. |
|
|
|
|
|
|
|
|
|
|
|
On peut terminer le programme avec `sys.exit()` et un numéro: |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> scores = { "Anne": 42, "Bernard": 5 } |
|
|
|
|
|
>>> score1 = scores.get("Anne") |
|
|
|
|
|
>>> score1 is None |
|
|
|
|
|
False |
|
|
|
|
|
>>> score2 = scores.get("Sophie") |
|
|
|
|
|
>>> score2 is None |
|
|
|
|
|
True |
|
|
|
|
|
|
|
|
import sys |
|
|
|
|
|
|
|
|
|
|
|
def fait_quelque_chose(): |
|
|
|
|
|
if erreur: |
|
|
|
|
|
sys.exit(1) |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# Lever l'ambiguïté |
|
|
|
|
|
|
|
|
Note: dans un vrai programme, veillez à construire et afficher un |
|
|
|
|
|
message utile! |
|
|
|
|
|
|
|
|
Notez qu'ici Sophie peut être dans le dictionnaire, mais avec une valeur 'None', |
|
|
|
|
|
ou bien ne pas y être. |
|
|
|
|
|
|
|
|
# Gestion du code de retour en Python (2) |
|
|
|
|
|
|
|
|
Attention aux ambiguïtés, donc! |
|
|
|
|
|
|
|
|
`sys.exit(0)` pour terminer immédiatement et sans erreur. |
|
|
|
|
|
|
|
|
Pas de méthode magique : il faut être au courant du problème. |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
import sys |
|
|
|
|
|
|
|
|
|
|
|
def antivirus(): |
|
|
|
|
|
problèmes = cherche_problèmes() |
|
|
|
|
|
|
|
|
# Retourner None |
|
|
|
|
|
|
|
|
if not problèmes: |
|
|
|
|
|
print("Aucun problème trouvé") |
|
|
|
|
|
sys.exit(0) |
|
|
|
|
|
|
|
|
`None` est aussi la valeur par défaut lorsqu'il n'y a pas de `return` |
|
|
|
|
|
dans le corps de la fonction: |
|
|
|
|
|
|
|
|
for problème in problèmes: |
|
|
|
|
|
# traite chaque problème un à un |
|
|
|
|
|
... |
|
|
|
|
|
```` |
|
|
|
|
|
|
|
|
|
|
|
# Gestion du code de retour en Python - un raccourci |
|
|
|
|
|
|
|
|
|
|
|
On peut passer le message d'erreur directement à `sys.exit()` avec |
|
|
|
|
|
une string au lieu d'un numéro: |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> def ne_retourne_rien(a, b): |
|
|
|
|
|
>>> c = a + b |
|
|
|
|
|
|
|
|
if erreur: |
|
|
|
|
|
sys.exit("Une erreur est survenue") |
|
|
|
|
|
|
|
|
>>> résultat = ne_retourne_rien(3, 2) |
|
|
|
|
|
>>> résultat is None |
|
|
|
|
|
True |
|
|
|
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# Retourner None au autre chose |
|
|
|
|
|
|
|
|
# Les arguments d'un programme |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
def trouve_dans_liste1(liste, element): |
|
|
|
|
|
if element in list: |
|
|
|
|
|
return liste.index(element) |
|
|
|
|
|
|
|
|
Pour lancer un programme, on tape son nom, suivi de mots séparés pas |
|
|
|
|
|
des espaces. |
|
|
|
|
|
|
|
|
|
|
|
En Python, ça donne |
|
|
|
|
|
|
|
|
def trouve_dans_liste2(liste, element): |
|
|
|
|
|
if element in list: |
|
|
|
|
|
return liste.index(element) |
|
|
|
|
|
else: |
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
``` |
|
|
|
|
|
python3 fichier.py arg1 arg2 |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
# Accès aux arguments en Python |
|
|
|
|
|
|
|
|
Les deux fonctions font la même chose! `trouve_dans_liste2` est simplement plus *explicite.* |
|
|
|
|
|
|
|
|
* `import sys` |
|
|
|
|
|
* `sys.argv` |
|
|
|
|
|
|
|
|
# Types optionnels |
|
|
|
|
|
|
|
|
`sys.argv` est une liste, et son premier argument est |
|
|
|
|
|
*toujours* le nom du fichier exécuté. |
|
|
|
|
|
|
|
|
|
|
|
# Exemple |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
def trouve_dans_liste(liste, element): |
|
|
|
|
|
if element in list: |
|
|
|
|
|
return liste.index(element) |
|
|
|
|
|
else: |
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
# Dans foo.py |
|
|
|
|
|
import sys |
|
|
|
|
|
print("Fichier source:", sys.argv[0]) |
|
|
|
|
|
print("Reste des arguments:", sys.argv[1:]) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
|
|
|
``` |
|
|
|
|
|
$ python3 foo.py un deux |
|
|
|
|
|
Fichier source: foo.py |
|
|
|
|
|
Reste des arguments: ['un', 'deux'] |
|
|
``` |
|
|
``` |
|
|
On dit aussi que le type de retour de `trouve_dans_liste` est *optionnel*. |
|
|
|
|
|
|
|
|
|
|
|
# |
|
|
# |
|
|
|
|
|
|
|
|
\center Les tuples |
|
|
|
|
|
|
|
|
\center \huge Cas pratique |
|
|
|
|
|
|
|
|
# Création de tuples |
|
|
|
|
|
|
|
|
# Squelette |
|
|
|
|
|
|
|
|
|
|
|
Décodeur de noms d'aéroports |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
mon_tuple = tuple() # un tuple vide |
|
|
|
|
|
mon_tuple = () # aussi un tuple vide |
|
|
|
|
|
mon_tuple = (1, 2) # un tuple à deux éléments |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
* Lire un fichier avec les codes et les noms associés |
|
|
|
|
|
* En faire un dictionnaire |
|
|
|
|
|
* Utiliser le premier argument comme nom de code |
|
|
|
|
|
* Afficher le nom complet de l'aéeroport, ou une |
|
|
|
|
|
erreur s'il est inconnu. |
|
|
|
|
|
|
|
|
# Note |
|
|
|
|
|
|
|
|
# Différentes approches |
|
|
|
|
|
|
|
|
C'est la virgule qui fait le tuple, pas les parenthèses |
|
|
|
|
|
(on n'utilise les parenthèse que pour l'esthétique) |
|
|
|
|
|
|
|
|
* Bottom-up (approche *ascendante*) |
|
|
|
|
|
* Top-Bottom (approche *descendante*) |
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
# Approches bottom-up |
|
|
|
|
|
|
|
|
|
|
|
Utilisé pour le pendu: |
|
|
|
|
|
|
|
|
|
|
|
* construire des blocs élémentaires (les petites fonctions `has_won`, |
|
|
|
|
|
`display_hint`, etc...) |
|
|
|
|
|
* les assembler pour faire un tout plus "haut niveau" (le corps de la |
|
|
|
|
|
fonction `main()` |
|
|
|
|
|
|
|
|
|
|
|
# Approche top-down |
|
|
|
|
|
|
|
|
|
|
|
Essayons de partir du plus "haut niveau" et de "descendre" vers les |
|
|
|
|
|
blocs élémentaires |
|
|
|
|
|
|
|
|
|
|
|
# Code |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
(1) |
|
|
|
|
|
# pas un tuple, juste le nombre 1 (entre parenthèses) |
|
|
|
|
|
(1,) |
|
|
|
|
|
# un tuple à un élément |
|
|
|
|
|
1, |
|
|
|
|
|
# le *même* tuple |
|
|
|
|
|
|
|
|
def main(): |
|
|
|
|
|
dico = fabrique_dico() |
|
|
|
|
|
code = lire_code() |
|
|
|
|
|
nom = trouve_code(code, dico) |
|
|
|
|
|
if nom: |
|
|
|
|
|
print(nom) |
|
|
|
|
|
else: |
|
|
|
|
|
affiche_erreur(code) |
|
|
|
|
|
|
|
|
|
|
|
main() |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# Indexation, test d'appartenance |
|
|
|
|
|
|
|
|
On a fait comme si le code dont on avait besoin était déjà écrit :) |
|
|
|
|
|
|
|
|
|
|
|
# lire_code() |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> couple = ('Starsky', 'Hutch') |
|
|
|
|
|
>>> couple[0] |
|
|
|
|
|
'Starsky' |
|
|
|
|
|
>>> couple[1] |
|
|
|
|
|
'Hutch' |
|
|
|
|
|
>>> couple[3] |
|
|
|
|
|
IndexError |
|
|
|
|
|
|
|
|
import sys |
|
|
|
|
|
|
|
|
|
|
|
def lire_code(): |
|
|
|
|
|
if len(sys.argv) < 2: |
|
|
|
|
|
print( |
|
|
|
|
|
"Pas assez d'arguments", |
|
|
|
|
|
file=sys.stderr |
|
|
|
|
|
) |
|
|
|
|
|
sys.exit(1) |
|
|
|
|
|
argument = sys.argv[1] |
|
|
|
|
|
# On accepte `cdg` ou `CDG`. |
|
|
|
|
|
code = argument.upper() |
|
|
|
|
|
return code |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# fabrique_dico() |
|
|
|
|
|
|
|
|
|
|
|
Le fichier `airports.txt` ressemble à ça: |
|
|
|
|
|
|
|
|
>>> 'Starsky' in couple |
|
|
|
|
|
True |
|
|
|
|
|
>>> 'Batman' in couple |
|
|
|
|
|
False |
|
|
|
|
|
|
|
|
``` |
|
|
|
|
|
CDG Paris-Charles de Gaulle |
|
|
|
|
|
ORY Paris-Orly |
|
|
|
|
|
NCE Nice-Côte d'Azur |
|
|
|
|
|
... |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
Rien de nouveau en principe :p |
|
|
|
|
|
|
|
|
Téléchargez-le ici: |
|
|
|
|
|
|
|
|
# Déstructuration |
|
|
|
|
|
|
|
|
\url{https://raw.githubusercontent.com/E2L/cours-python/master/sources/airports.txt} |
|
|
|
|
|
|
|
|
Créer plusieurs variables en une seule ligne |
|
|
|
|
|
|
|
|
Clique droit / Enregistrer sous / airports.txt |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
>>> couple = ("Batman", "Robin") |
|
|
|
|
|
>>> héro, side_kick = couple |
|
|
|
|
|
>>> héro |
|
|
|
|
|
'Batman' |
|
|
|
|
|
>>> side_kick |
|
|
|
|
|
'Robin' |
|
|
|
|
|
|
|
|
# fabrique_dico() - 2 |
|
|
|
|
|
|
|
|
>>> héro, side_kick, ennemi = couple |
|
|
|
|
|
ValueError 3 != 2 |
|
|
|
|
|
>>> héro, = couple |
|
|
|
|
|
ValueError 1 != 2 |
|
|
|
|
|
ValueError |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
def fabrique_dico(): |
|
|
|
|
|
dico = dict() |
|
|
|
|
|
fichier = open("airports.txt", "r") |
|
|
|
|
|
contenu = fichier.read() |
|
|
|
|
|
fichier.close() |
|
|
|
|
|
|
|
|
>>> héro = couple |
|
|
|
|
|
# OK, mais la variable héro est maintenant un tuple ... |
|
|
|
|
|
|
|
|
lignes = contenu.splitlines() |
|
|
|
|
|
for ligne in lignes: |
|
|
|
|
|
code = ligne[0:3] |
|
|
|
|
|
nom = ligne[4:] |
|
|
|
|
|
dico[code] = nom |
|
|
|
|
|
return dico |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# On peut aussi déstructurer des listes |
|
|
|
|
|
|
|
|
# trouve_code() |
|
|
|
|
|
|
|
|
```python |
|
|
```python |
|
|
>>> fruits = ["pomme", "banane", "orange"] |
|
|
|
|
|
>>> premier, deuxième, troisième = fruits |
|
|
|
|
|
|
|
|
def trouve_code(code, dico): |
|
|
|
|
|
if code in dico: |
|
|
|
|
|
return dico[code] |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
# Retours multiple |
|
|
|
|
|
|
|
|
\vfill |
|
|
|
|
|
|
|
|
Retourner plusieurs valeurs: |
|
|
|
|
|
|
|
|
Notez le `return None` implicite! |
|
|
|
|
|
|
|
|
#TODO: better Exemple, pleaz |
|
|
|
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
def age_sexe_ville(pseudo): |
|
|
|
|
|
age = ... |
|
|
|
|
|
sexe = .. |
|
|
|
|
|
ville = ... |
|
|
|
|
|
return (age, sexe, ville) |
|
|
|
|
|
|
|
|
# affiche_erreur() |
|
|
|
|
|
|
|
|
(a, s, v) = age_sexe_ville('kevin') |
|
|
|
|
|
# on dit aussi: unpacking |
|
|
|
|
|
|
|
|
```python |
|
|
|
|
|
def affiche_erreur(code): |
|
|
|
|
|
print( |
|
|
|
|
|
"Code:", code, |
|
|
|
|
|
"non trouvé", |
|
|
|
|
|
file=sys.stderr |
|
|
|
|
|
) |
|
|
|
|
|
sys.exit(2) |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
Notes: |
|
|
|
|
|
|
|
|
|
|
|
* on affiche le code qu'on a pas trouvé (c'est utile de l'avoir dans |
|
|
|
|
|
le message) |
|
|
|
|
|
* valeur d'erreur différente du cas où il n'y avait pas assez |
|
|
|
|
|
d'arguments |
|
|
|
|
|
|
|
|
|
|
|
# Rappel du `main()` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
``` |
|
|
``` |
|
|
a -> 14 |
|
|
|
|
|
s -> M |
|
|
|
|
|
v -> Paris |
|
|
|
|
|
|
|
|
def main(): |
|
|
|
|
|
dico = fabrique_dico() |
|
|
|
|
|
code = lire_code() |
|
|
|
|
|
nom = trouve_code(code, dico) |
|
|
|
|
|
if nom: |
|
|
|
|
|
print(nom) |
|
|
|
|
|
else: |
|
|
|
|
|
affiche_erreur(code) |
|
|
|
|
|
|
|
|
|
|
|
main() |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
# |
|
|
|
|
|
|
|
|
|
|
|
\centering \huge Démo |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Pour la prochaine fois |
|
|
|
|
|
|
|
|
|
|
|
Prenez le temps de réfléchir :) |
|
|
|
|
|
|
|
|
|
|
|
Quelle approche avez-vous préféré ? Pourquoi ? |