Update first chapters and new questions
Updated first chapter slides. Added new questions in the new training section.
This commit is contained in:
@ -1,30 +1,39 @@
|
|||||||
---
|
---
|
||||||
title: Découvrir le langage - types de données avancés
|
title: Découvrir le langage - collections
|
||||||
author: Steve Kossouho
|
author: Steve Kossouho
|
||||||
---
|
---
|
||||||
|
|
||||||
# Collections de données
|
# Collections de données
|
||||||
|
|
||||||
|
Ce chapitre va présenter 4 types de données de base, qui permettent de manipuler plusieurs informations avec une seule
|
||||||
|
variable :
|
||||||
|
|
||||||
|
- Listes
|
||||||
|
- Tuples
|
||||||
|
- Ensembles
|
||||||
|
- Dictionnaires
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Les listes
|
## Listes
|
||||||
|
|
||||||
Type de collection de données : `list`{.python}. Une liste peut contenir une **séquence** d'éléments
|
Type de collection de données le plus utile : `list`{.python}. Un objet de type liste peut contenir une **séquence** d'éléments
|
||||||
de n'importe quel type pris en charge par Python, y compris d'autres listes. Le contenu d'une liste est modifiable (ajouter, retirer des éléments…)
|
de n'importe quel type en Python, y compris d'autres listes. Le contenu d'une liste est modifiable (ajouter, retirer des éléments…)
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
liste1 = [1, 2, 3, 4, 5, 6] # types cohérents
|
liste1 = [1, 2, 3, 4, 5, 6] # éléments de types cohérents
|
||||||
liste2 = [1, 2, 3, "a", "b", "c"] # types divers
|
liste2 = [1, 2, 3, "a", "b", "c"] # pas de restriction sur les types
|
||||||
liste3 = [None, None, True, False]
|
liste3 = [None, None, True, False] # None n'est pas une valeur spéciale
|
||||||
liste4 = [[1, 2, 3], [4, 5, 6]]
|
liste4 = [[1, 2, 3], [4, 5, 6]]
|
||||||
liste5 = [] # liste vide, équivalent à list()
|
liste5 = [] # liste vide. Équivalent à list()
|
||||||
liste6 = [liste1] # Liste contenant 1 élément, qui est lui-même une liste
|
liste6 = [liste1] # Liste contenant 1 élément, qui est lui-même une liste
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Il est possible de manipuler une liste facilement. On peut ajouter des éléments à la fin, à une
|
Il est possible d'exploiter une liste facilement; on peut ajouter de nouveaux éléments à la fin, les insérer à une
|
||||||
position précise, retirer un élément ou encore récupérer un élément seul.
|
position précise, retirer un élément ou encore récupérer un élément seul. Notez que les positions ([index]{.naming})
|
||||||
|
des éléments démarrent à zéro (`0`) et qu'une liste n'a jamais d'emplacement vide.
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
liste1 = [1, 2, 3, 4, 5, 6]
|
liste1 = [1, 2, 3, 4, 5, 6]
|
||||||
@ -34,8 +43,10 @@ liste2 = list() # Créer une nouvelle liste vide
|
|||||||
length = len(liste1) # Récupérer le nombre d'éléments
|
length = len(liste1) # Récupérer le nombre d'éléments
|
||||||
position = liste1.index(3) # Renvoie l'index de la valeur 3, ou erreur si introuvable
|
position = liste1.index(3) # Renvoie l'index de la valeur 3, ou erreur si introuvable
|
||||||
nine_trouvable = 9 in liste1 # Renvoie si l'élément 9 existe dans la liste
|
nine_trouvable = 9 in liste1 # Renvoie si l'élément 9 existe dans la liste
|
||||||
|
|
||||||
# Récupérer des éléments
|
# Récupérer des éléments
|
||||||
print(liste1[0]) # Affiche le premier élément si la liste est non vide
|
print(liste1[0]) # Affiche le premier élément si la liste est non vide
|
||||||
|
|
||||||
# Manipuler le contenu
|
# Manipuler le contenu
|
||||||
liste1.append(7) # Ajoute 7 comme nouvel élément à la fin
|
liste1.append(7) # Ajoute 7 comme nouvel élément à la fin
|
||||||
liste1.insert(0, 99) # Insère 99 comme nouvel élément au tout début
|
liste1.insert(0, 99) # Insère 99 comme nouvel élément au tout début
|
||||||
@ -64,31 +75,33 @@ if len(liste1) >= 4:
|
|||||||
|
|
||||||
### Erreurs de méthodes
|
### Erreurs de méthodes
|
||||||
|
|
||||||
La méthode `.remove(valeur)`{.python} provoque également une erreur (`ValueError`{.python}) si
|
Les méthodes `list.remove()`{.python} et `list.index()`{.python} provoquent également une erreur (`ValueError`{.python}) si
|
||||||
l'élément en argument n'existe pas dans la liste. De la même façon, il peut être utile de tester
|
l'élément en argument est introuvable dans la liste. De la même façon, il peut être utile de tester
|
||||||
qu'un élément est présent dans la liste avant d'essayer de l'en supprimer :
|
qu'un élément est présent dans la liste avant d'essayer de l'en supprimer :
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
liste1 = [1, 2, 3]
|
liste1 = ["fred", "denis", 14, 23, 32]
|
||||||
if 8 in liste1:
|
if 8 in liste1: # Tester que 8 a été trouvé dans la liste
|
||||||
liste1.remove(8)
|
liste1.remove(8)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Question** : Qu'écririez-vous pour supprimer toutes les occurrences d'une valeur en utilisant `list.remove()`{.python} ?
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### Indices de liste négatifs
|
### Indices de liste négatifs
|
||||||
|
|
||||||
Il est également possible d'accéder à des éléments de liste en utilisant des indices négatifs.
|
Il est également possible d'accéder à des éléments de liste **non vide** en utilisant des indices négatifs.
|
||||||
|
|
||||||
Si la liste n'est pas vide, l'élément d'indice `-1` est le dernier élément de la liste (équivalent
|
Dans ce cas, l'élément à l'index `-1` d'une liste `l` est celui à l'index `len(l) - 1`{.python}, à savoir
|
||||||
à `len(liste) - 1`{.python}), et l'élément à l'indice `-len(liste)`{.python} est le premier (
|
le dernier élément. L'élément à l'index `-len(l)`{.python} sera celui à l'index `0`, à savoir le premier
|
||||||
équivalent à `0`).
|
élément. Tout index hors de la plage disponible provoquera une erreur de type `IndexError`{.python}.
|
||||||
|
|
||||||
Tout nombre inférieur génère une erreur de type `IndexError`{.python}.
|
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
liste1 = [1, 2, 4, 6, 9, 11]
|
animals = ["dog", "cat", "rabbit", "hamster", "parrot"]
|
||||||
print(liste1[-1])
|
print(animals[-1]) # affiche "parrot"
|
||||||
|
print(animals[-2]) # affiche "hamster"
|
||||||
|
print(animals[-5]) # affiche "dog"
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
@ -96,7 +109,7 @@ print(liste1[-1])
|
|||||||
## Parcourir une liste
|
## Parcourir une liste
|
||||||
|
|
||||||
Comme on l'a vu avec la boucle `for`{.python}, utilisée avec `range()`{.python}, on peut utiliser la
|
Comme on l'a vu avec la boucle `for`{.python}, utilisée avec `range()`{.python}, on peut utiliser la
|
||||||
boucle `for`{.python} sur une liste :
|
boucle `for`{.python} sur une liste :
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
prime_numbers = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
|
prime_numbers = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
|
||||||
@ -110,37 +123,28 @@ les valeurs `2`{.python}, puis `3`{.python}, puis `5`{.python}, etc.
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Opérations sur listes
|
### Opérations sur listes
|
||||||
|
|
||||||
Récupérer des portions ou partitions de listes (slicing) :
|
Récupérer des portions ou partitions de listes est possible en Python avec la syntaxe suivante (slicing).
|
||||||
|
Le comportement de cette syntaxe est basé sur le fonctionnement de la fonction `range`{.python}.
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
a = [10, 15, 20, 25, 30, 35, 40, 45, 50, 55]
|
a = [10, 15, 20, 25, 30, 35, 40, 45, 50, 55] # liste de base
|
||||||
b = a[0:5] # Index 0 à 5 non inclus. Marche aussi sur les chaînes.
|
b = a[0:5] # copier dans une nouvelle liste les éléments aux index 0 à 4.
|
||||||
c = a[5:0] # L'index de fin est inférieur au départ, renvoie une liste vide
|
c = a[5:0] # créer une nouvelle liste, mais ne rien y copier
|
||||||
d = a[:] # Renvoie une copie de toute la liste
|
d = a[:] # copier de l'extrêmité gauche à droite incluses
|
||||||
e = a[::-1] # Tout parcourir à l'envers
|
e = a[::-1] # copier tous les éléments à l'envers
|
||||||
f = a[::2] # Tout parcourir 2 par 2
|
f = a[::2] # Tout parcourir 2 par 2
|
||||||
g = a[5:2:-1] # L'indice de début est supérieur à l'indice de fin
|
g = a[5:2:-1] # L'indice de début est supérieur à l'indice de fin
|
||||||
h = a[2:5:-1] # Le pas est négatif, start < end, renvoie une liste vide
|
h = a[2:5:-1] # Le pas est négatif, start < end, renvoie une liste vide
|
||||||
```
|
```
|
||||||
|
|
||||||
Pourquoi créer des portions de listes ? Cela peut-être utile, par exemple, si
|
Pourquoi créer des portions de listes ? Cela peut-être utile, par exemple, si
|
||||||
vous souhaitez appliquer un calcul sur une petite partition d'un jeu de données.
|
vous souhaitez appliquer un calcul sur une petite partition d'un jeu de données.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Autres collections
|
## Tuples
|
||||||
|
|
||||||
Outre les listes, il existe 3 types de base pour collectionner des éléments :
|
|
||||||
|
|
||||||
- Tuple : `tuple()`{.python}
|
|
||||||
- Set (jeu d'éléments uniques) : `set()`{.python}
|
|
||||||
- Dictionnaires (association) : `dict()`{.python}
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
### Tuples
|
|
||||||
|
|
||||||
**Tuple** : Un `tuple`{.python} fonctionne quasiment trait pour trait comme une liste, à la différence qu'une
|
**Tuple** : Un `tuple`{.python} fonctionne quasiment trait pour trait comme une liste, à la différence qu'une
|
||||||
fois que vous avez défini ses éléments, vous ne pouvez plus en changer. On parle de « collection immuable ».
|
fois que vous avez défini ses éléments, vous ne pouvez plus en changer. On parle de « collection immuable ».
|
||||||
@ -157,7 +161,7 @@ ce type : [opérations des tuples](https://docs.python.org/3/library/stdtypes.h
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### Ensembles (données uniques)
|
## Ensembles (données uniques)
|
||||||
|
|
||||||
**Set** (ensemble) : Un `set`{.python} peut contenir plusieurs éléments et est modifiable au même titre
|
**Set** (ensemble) : Un `set`{.python} peut contenir plusieurs éléments et est modifiable au même titre
|
||||||
qu'une liste, mais n'est pas une séquence; aucune notion d'ordre ou d'index.
|
qu'une liste, mais n'est pas une séquence; aucune notion d'ordre ou d'index.
|
||||||
@ -168,11 +172,14 @@ dans votre objet.
|
|||||||
a = {1, 1, 2, 3, 3, 3} # équivaut à {1, 2, 3}, les valeurs étant uniques à la fin
|
a = {1, 1, 2, 3, 3, 3} # équivaut à {1, 2, 3}, les valeurs étant uniques à la fin
|
||||||
b = {2, 4, 5, "hello", (1, 2, 3)}
|
b = {2, 4, 5, "hello", (1, 2, 3)}
|
||||||
c = set() # obligatoire pour déclarer un set vide, sinon considéré dict
|
c = set() # obligatoire pour déclarer un set vide, sinon considéré dict
|
||||||
|
|
||||||
print(len(b))
|
print(len(b))
|
||||||
|
|
||||||
a.add(9.5) # ajoute la valeur 9.5 (float) au set
|
a.add(9.5) # ajoute la valeur 9.5 (float) au set
|
||||||
a.discard(9.5) # retire la valeur 9.5, ou ne fait rien
|
a.discard(9.5) # retire la valeur 9.5, ou ne fait rien
|
||||||
d = a.intersection(b) # renvoie un set avec les éléments communs à a et b
|
|
||||||
e = a.union(b) # avec les éléments présents dans a ou b
|
d = a.intersection(b) # récupérer un ensemble avec les éléments communs à a et b
|
||||||
|
e = a.union(b) # récupérer un ensemble avec les éléments présents dans a ou b
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -184,18 +191,18 @@ e = a.union(b) # avec les éléments présents dans a ou b
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
#### Bonus : Particularités des ensembles
|
### Bonus : Particularités des ensembles
|
||||||
|
|
||||||
Les ensembles sont des structures de données très efficaces. Techniquement, vous pouvez attendre une
|
Les ensembles sont des structures de données très efficaces. Techniquement, vous pouvez attendre une
|
||||||
complexité en `O(1)` pour que Python sache si un élément est déjà présent ou pas; cela signifie qu'il
|
complexité en `O(1)` pour que Python sache si un élément est déjà présent ou pas; cela signifie qu'il
|
||||||
faut plus ou moins le même nombre d'opérations pour trouver un élément, que votre `set`{.python} en possède un
|
faut plus ou moins le même nombre d'opérations pour trouver un élément, que votre `set`{.python} en contienne un
|
||||||
seul ou un milliard.
|
seul ou un milliard.
|
||||||
|
|
||||||
L'algorithme et la structure de données interne à Python derrière cette efficacité se nomme **Table de hachage**.
|
L'algorithme et la structure de données interne à Python derrière cette efficacité se nomme [Table de hachage]{.naming}.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
##### Tables de hachage
|
#### Tables de hachage
|
||||||
|
|
||||||
Une table de hachage fonctionne en trois temps :
|
Une table de hachage fonctionne en trois temps :
|
||||||
|
|
||||||
@ -206,13 +213,13 @@ Une table de hachage fonctionne en trois temps :
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
##### Exemple de hachage
|
#### Exemple de hachage
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
##### Hachage
|
#### Hachage
|
||||||
|
|
||||||
La signature est un nombre calculé qui est sensé dépendre du contenu d'un objet. Python propose une fonction
|
La signature est un nombre calculé qui est sensé dépendre du contenu d'un objet. Python propose une fonction
|
||||||
à cet effet, `hash()`{.python}, pour laquelle chaque classe propose sa propre implémentation.
|
à cet effet, `hash()`{.python}, pour laquelle chaque classe propose sa propre implémentation.
|
||||||
@ -223,7 +230,7 @@ il n'y a pas de collision.
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
##### Hachage en général dans Python
|
#### Hachage en général dans Python
|
||||||
|
|
||||||
Entre deux lancements d'un interpréteur Python, le hash de la majorité des objets est différent;
|
Entre deux lancements d'un interpréteur Python, le hash de la majorité des objets est différent;
|
||||||
l'algorithme utilise une valeur aléatoire pour générer les hashs, de façon qu'il soit impossible de créer un
|
l'algorithme utilise une valeur aléatoire pour générer les hashs, de façon qu'il soit impossible de créer un
|
||||||
@ -238,7 +245,7 @@ Le hachage est en général imprévisible pour les valeurs suivantes :
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
##### Hashes prévisibles
|
#### Hashes prévisibles
|
||||||
|
|
||||||
Le hash est par contre prévisible pour les valeurs suivantes :
|
Le hash est par contre prévisible pour les valeurs suivantes :
|
||||||
|
|
||||||
@ -255,7 +262,7 @@ Les objets `int`{.python} ont généralement un `hash()`{.python} identique, sau
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
##### Hashes impossibles
|
#### Hashes impossibles
|
||||||
|
|
||||||
L'algorithme de la table de hachage nécessite qu'un objet stocké dans un bucket possède en
|
L'algorithme de la table de hachage nécessite qu'un objet stocké dans un bucket possède en
|
||||||
permanence un `hash` correspondant à son bucket. Cela pose un problème avec les objets modifiables
|
permanence un `hash` correspondant à son bucket. Cela pose un problème avec les objets modifiables
|
||||||
@ -263,50 +270,57 @@ permanence un `hash` correspondant à son bucket. Cela pose un problème avec le
|
|||||||
|
|
||||||
La solution adoptée par Python consiste à interdire le calcul de signature desdits objets.
|
La solution adoptée par Python consiste à interdire le calcul de signature desdits objets.
|
||||||
Les `tuple`{.python} demeurent des données valides, puisque nous avons la garantie de ne jamais pouvoir
|
Les `tuple`{.python} demeurent des données valides, puisque nous avons la garantie de ne jamais pouvoir
|
||||||
changer leur contenu, et ainsi leur signature.
|
changer leur contenu, et par là-même leur signature.
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
# La fonction hash est disponible par défaut en Python
|
# La fonction hash est disponible par défaut en Python
|
||||||
print(hash([1, 2, 3])) # Provoque une exception
|
print(hash([1, 2, 3])) # Provoque une exception
|
||||||
|
print(hash({1, 2, 3})) # Même problème
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### Dictionnaires : associations entre clés et valeurs
|
## Dictionnaires : associations entre clés et valeurs
|
||||||
|
|
||||||
**Dictionnaires** : (`dict`{.python}) C'est un **ensemble** d'associations où l'on définit clés et valeurs. C'est le même
|
**Dictionnaires** : (`dict`{.python}) C'est un **ensemble** d'associations où l'on définit [clés]{.naming} et [valeurs]{.naming}.
|
||||||
fonctionnement qu'un dictionnaire lexicographique, où, lorsque vous avez le
|
C'est le même fonctionnement qu'un dictionnaire lexicographique, où, lorsque vous avez le
|
||||||
mot (la clé), vous retrouvez la définition s'il y en a une (la valeur). D'autres langages ont des structures
|
mot (la clé), vous retrouvez la définition s'il y en a une (la valeur).
|
||||||
similaires et appellent ça des `HashMap`{.java} ou des `object`{.javascript}.
|
D'autres langages ont des structures similaires et appellent ça des `HashMap`{.java} ou des `object`{.javascript}.
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
a = {"server1": "192.168.1.2", "server2": "192.168.1.3", "server3": "192.168.1.5"} # serveurs et adresses IP
|
a = {"server1": "192.168.1.2", "server2": "192.168.1.3", "server3": "192.168.1.5"} # serveurs et adresses IP
|
||||||
b = {8: "Mme Garnier", 10: "M. Dubois", 11: "Mlle Yousfi", 12: "Mme Préjean"} # rendez-vous horaires
|
b = {8: "Mme Garnier", 10: "M. Dubois", 11: "Mlle Yousfi", 12: "Mme Préjean"} # rendez-vous horaires
|
||||||
d = {1.2: "flottant", True: "booléen", None: "rien", (1, 2, 3): "tuple"} # clés de plusieurs types
|
d = {1.2: "flottant", True: "booléen", None: "rien", (1, 2, 3): "tuple"} # clés de plusieurs types
|
||||||
c = {} # ou dict(), ceci est un dictionnaire vide
|
c = {} # ou dict(), ceci est un dictionnaire vide
|
||||||
|
|
||||||
print(a["server1"]) # affiche "192.168.1.2"
|
print(a["server1"]) # affiche "192.168.1.2"
|
||||||
print(b[10]) # affiche "M. Dubois"
|
print(b[10]) # affiche "M. Dubois"
|
||||||
print(b[9]) # provoque une erreur
|
print(b[9]) # provoque une erreur
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Les dictionnaires ont les mêmes contraintes que les ensembles uniquement au niveau de leurs clés; vous
|
||||||
|
pouvez uniquement utiliser des valeurs de types immuables, tels que `int`{.python}, `float`{.python}, `tuple`{.python}...
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
#### Parcourir un dictionnaire
|
#### Parcourir un dictionnaire
|
||||||
|
|
||||||
Il est possible de parcourir un dictionnaire avec une boucle `for`{.python}. De base, ce sont les
|
Il est possible de parcourir un dictionnaire avec une boucle `for`{.python}. Dans ce cas, ce sont
|
||||||
clés du dictionnaire qui sont parcourues. Mais il existe des variantes assez pratiques pour
|
uniquement les clés du dictionnaire qui sont parcourues. Mais il existe des variantes assez pratiques pour
|
||||||
parcourir un dictionnaire :
|
parcourir un dictionnaire :
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
a = {
|
profils = {
|
||||||
"Jérémy": (25, "M", "Lille"),
|
"Jérémy": (25, "M", "Lille"),
|
||||||
"Hélène": (30, "F", "Ambérieu-en-Bugey"),
|
"Hélène": (30, "F", "Ambérieu-en-Bugey"),
|
||||||
"Gwladys": (35, "F", "Nyons"),
|
"Gwladys": (35, "F", "Nyons"),
|
||||||
|
"Thierry": (40, "M", "Montceau-les-Mines"),
|
||||||
|
"Carole": (45, "F", "Saint-Rémy-lès-Chevreuse"),
|
||||||
}
|
}
|
||||||
|
|
||||||
for prenom in a:
|
for prenom in profils:
|
||||||
print(prenom) # affiche uniquement une clé
|
print(prenom) # affiche uniquement une clé
|
||||||
print(a[prenom]) # retrouve la valeur associée à la clé
|
print(profils[prenom]) # retrouve la valeur associée à la clé
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
@ -316,11 +330,12 @@ de `n` éléments, vous pouvez les dépaqueter (**unpacking**) :
|
|||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
# Avancé, unpacking via la méthode `items`
|
# Avancé, unpacking via la méthode `items`
|
||||||
|
profils = {...}
|
||||||
|
|
||||||
for item in a.items(): # a.items() renvoie ((clé1, valeur1), (clé2, valeur2), …)
|
for item in profils.items(): # a.items() renvoie ((clé1, valeur1), (clé2, valeur2), …)
|
||||||
print(item) # est un tuple
|
print(item) # est un tuple
|
||||||
|
|
||||||
for key, value in a.items():
|
for key, value in profils.items():
|
||||||
# on peut utiliser 2 variables de boucle si chaque élément parcouru est
|
# on peut utiliser 2 variables de boucle si chaque élément parcouru est
|
||||||
# une séquence de taille 2. Merci l'unpacking !
|
# une séquence de taille 2. Merci l'unpacking !
|
||||||
print(key, value)
|
print(key, value)
|
||||||
@ -334,18 +349,22 @@ Pour changer la valeur associée à une clé existante, ou par la même occasion
|
|||||||
une nouvelle clé, il suffit d'écrire :
|
une nouvelle clé, il suffit d'écrire :
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
a = {"Bordeaux": 250000}
|
populations = {"Bordeaux": 250000, "Cherbourg": 80000}
|
||||||
a["Marseille"] = 800000
|
print(populations)
|
||||||
a["Bordeaux"] = 90
|
|
||||||
print(a["Bordeaux"]) # Affiche 90
|
# Modifier le contenu
|
||||||
|
populations["Marseille"] = 800000
|
||||||
|
populations["Bordeaux"] = 90
|
||||||
|
print(populations["Bordeaux"]) # Affiche 90
|
||||||
|
|
||||||
# On peut supprimer du dictionnaire une association en écrivant
|
# On peut supprimer du dictionnaire une association en écrivant
|
||||||
del a["Marseille"] # plus de clé pour Marseille !
|
del populations["Marseille"] # plus de clé pour Marseille !
|
||||||
print("Marseille" in a) # renvoie si la clé "Marseille" existe
|
print("Marseille" in populations) # renvoie si la clé "Marseille" existe
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### Plus : méthodes de dictionnaires
|
### Extra : méthodes de dictionnaires
|
||||||
|
|
||||||
La méthode `get(key, default)`{.python} des dictionnaires renvoie la valeur associée à une clé. Si
|
La méthode `get(key, default)`{.python} des dictionnaires renvoie la valeur associée à une clé. Si
|
||||||
l'on ne passe pas de valeur pour l'argument `default`{.python}, pour une clé introuvable, la méthode
|
l'on ne passe pas de valeur pour l'argument `default`{.python}, pour une clé introuvable, la méthode
|
||||||
@ -415,9 +434,9 @@ Nous n'avons pas vu grand chose sur les chaînes de caractères, mais certaines
|
|||||||
- [Documentation officielle sur le format des interpolations](https://docs.python.org/3/library/string.html#format-string-syntax)
|
- [Documentation officielle sur le format des interpolations](https://docs.python.org/3/library/string.html#format-string-syntax)
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
a = 19
|
number = 2_643
|
||||||
b = f"Le serveur qui doit être vérifié aujourd'hui est le numéro {a}"
|
print(f"Le serveur qui doit être vérifié aujourd'hui est le numéro {number}")
|
||||||
c = f"Formatage de la variable : {a:f}" # affiché comme flottant (6 chiffres après la virgule)
|
print(f"Formatage de la variable : {number:f}") # affiché comme flottant (6 chiffres après la virgule)
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
@ -430,7 +449,7 @@ print(chaine.upper(), chaine.lower())
|
|||||||
print(chaine.center(50, " ")) # Centre la chaîne originale sur 50 caractères
|
print(chaine.center(50, " ")) # Centre la chaîne originale sur 50 caractères
|
||||||
```
|
```
|
||||||
|
|
||||||
Méthodes qui renvoient une copie modifiée d'une chaîne
|
Méthodes qui renvoient une **copie** modifiée d'une chaîne
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -457,37 +476,4 @@ print("17 juillet" in chaine)
|
|||||||
|
|
||||||
Exemple de `str.split()`{.python} et `str.join()`{.python}
|
Exemple de `str.split()`{.python} et `str.join()`{.python}
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Bonus : Convertir des données d'un type à un autre
|
|
||||||
|
|
||||||
Nous avons vu, ici et là, quelques fonctions pour déclarer des valeurs de base, ou convertir des
|
|
||||||
valeurs. En voici une liste plus complète :
|
|
||||||
|
|
||||||
- `bool(val)`{.python}
|
|
||||||
- `int(val)`{.python}, `float(val)`{.python}
|
|
||||||
- `str(val)`{.python}
|
|
||||||
- `list(val)`{.python}, `tuple(val)`{.python}
|
|
||||||
- `set(val)`{.python}, `dict(val)`{.python}
|
|
||||||
|
|
||||||
Toutes ces fonctions renvoient un nouveau booléen, entier, flottant etc. correspondant à une
|
|
||||||
conversion de l'expression passée en argument. Cela fonctionne uniquement lorsque la conversion a du sens.
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Appelées sans argument, ces fonctions vous renvoient `False`{.python}, `0`{.python}, une chaîne ou une
|
|
||||||
collection vide (des valeurs considérées neutres, qui renvoient toujours `False`{.python} lorsqu'on les convertit en booléen).
|
|
||||||
|
|
||||||
Lorsque vous passez un argument à ces fonctions, elles vous renvoient une nouvelle valeur,
|
|
||||||
qui est une conversion de l'argument passé vers le type
|
|
||||||
représenté par la fonction. Ce n'est pas toujours possible d'effectuer une conversion; par exemple, il est impossible de
|
|
||||||
convertir une liste vers un nombre flottant, ou encore de convertir la chaîne `"bonjour"`{.python} vers un nombre entier.
|
|
||||||
|
|
||||||
```python {.numberLines}
|
|
||||||
converted1 = int(3.14159) # tronque le flottant / retire la partie décimale
|
|
||||||
converted3 = float("3.14159") # comprend le texte et génère un flottant
|
|
||||||
converted2 = list(1) # erreur
|
|
||||||
converted4 = float("salut") # aucun caractère valide pour représenter un nombre, échoue
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -630,3 +630,36 @@ Avec ce type d'expression, on pourra plutôt écrire :
|
|||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
variable = a if condition else b
|
variable = a if condition else b
|
||||||
```
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
### Extra : Convertir des données d'un type à un autre
|
||||||
|
|
||||||
|
Nous avons vu, ici et là, quelques fonctions pour déclarer des valeurs de base, ou convertir des
|
||||||
|
valeurs. En voici une liste plus complète :
|
||||||
|
|
||||||
|
- `bool(val)`{.python}
|
||||||
|
- `int(val)`{.python}, `float(val)`{.python}
|
||||||
|
- `str(val)`{.python}
|
||||||
|
- `list(val)`{.python}, `tuple(val)`{.python}
|
||||||
|
- `set(val)`{.python}, `dict(val)`{.python}
|
||||||
|
|
||||||
|
Toutes ces fonctions renvoient un nouveau booléen, entier, flottant etc. correspondant à une
|
||||||
|
conversion de l'expression passée en argument. Cela fonctionne uniquement lorsque la conversion a du sens.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Appelées sans argument, ces fonctions vous renvoient `False`{.python}, `0`{.python}, une chaîne ou une
|
||||||
|
collection vide (des valeurs considérées neutres, qui renvoient toujours `False`{.python} lorsqu'on les convertit en booléen).
|
||||||
|
|
||||||
|
Lorsque vous passez un argument à ces fonctions, elles vous renvoient une nouvelle valeur,
|
||||||
|
qui est une conversion de l'argument passé vers le type
|
||||||
|
représenté par la fonction. Ce n'est pas toujours possible d'effectuer une conversion; par exemple, il est impossible de
|
||||||
|
convertir une liste vers un nombre flottant, ou encore de convertir la chaîne `"bonjour"`{.python} vers un nombre entier.
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
|
converted1 = int(3.14159) # tronque le flottant / retire la partie décimale
|
||||||
|
converted3 = float("3.14159") # comprend le texte et génère un flottant
|
||||||
|
converted2 = list(1) # erreur
|
||||||
|
converted4 = float("salut") # aucun caractère valide pour représenter un nombre, échoue
|
||||||
|
```
|
||||||
|
@ -9,26 +9,36 @@ author: Steve Kossouho
|
|||||||
|
|
||||||
## Exceptions
|
## Exceptions
|
||||||
|
|
||||||
En Python, une exception est une erreur qui se produit pendant l'exécution de votre code. En tant que développeur, vous pouvez choisir ce que vous souhaitez faire quand une exception se produit, plutôt que de laisser le programme s'arrêter avec un message d'erreur. Les exceptions s'opposent entre autres aux erreurs de syntaxe, où l'interpréteur n'est pas même en mesure d'exécuter votre code.
|
En Python, une [exception]{.naming} est une erreur qui se produit pendant l'exécution de votre code.
|
||||||
|
En tant que développeur, vous pouvez **intercepter** une exception, et dire à Python ce que vous souhaitez faire
|
||||||
|
afin d'empêcher le programme de se terminer prématurément si ce n'est pas nécessaire.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### Jargon des exceptions
|
### Jargon des exceptions
|
||||||
|
|
||||||
- `Lever une exception` : Ce que Python effectue lorsqu'on rencontre une erreur à l'exécution d'un script. Les exceptions générées par Python sont d'un type qui dépend de l'erreur rencontrée. Elles font toutes partie d'une hiérarchie dont le type le plus générique est nommé `Exception`. (voir programmation orientée objet et hiérarchie des classes d'exception)
|
- [Lever une exception]{.naming} : Ce que Python effectue lorsqu'on rencontre une erreur à l'exécution d'un script.
|
||||||
- `Traceback` : <span style="color:red">Texte qui apparaît</span> dans la sortie d'erreur (en rouge) lorsque votre programme plante à l'exécution. C'est un récapitulatif des exécutions d'instructions qui ont mené directement à l'interruption de l'exécution, accompagné d'informations sur l'exception.
|
- [Traceback]{.naming} : <span style="color:#F04">Texte qui apparaît</span> dans la sortie d'erreur (en rouge) lorsque votre programme plante à l'exécution. C'est un récapitulatif des exécutions d'instructions qui ont mené directement à l'interruption de l'exécution, accompagné d'informations sur l'exception.
|
||||||
|
|
||||||
|
Les exceptions levées par Python sont d'un type qui dépend de l'erreur rencontrée (ex. `TypeError`{.python}).
|
||||||
|
Tous ces types font partie d'une hiérarchie dont le type le plus générique est nommé `Exception`.
|
||||||
|
Théoriquement, un développeur peut créer son propre type d'exception lorsqu'il développe des bibliothèques.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### Exemple d'exception
|
### Exemple de gestion d'exception
|
||||||
|
|
||||||
Dans l'exemple ci-dessous, on effectue une division par zéro, mais on pourrait accéder à un mauvais indice de liste, une mauvaise clé de dictionnaire, un fichier verrouillé…
|
Dans l'exemple ci-dessous, on effectue une division par zéro, ce qui est toujours une erreur, mais on pourrait accéder
|
||||||
|
à un mauvais index de liste, à une clé de dictionnaire inexistante, ou encore à un fichier verrouillé…
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
try:
|
try:
|
||||||
15 / 0 # erreur évidente pour l'exemple
|
resultat = 15 / 0 # erreur évidente pour l'exemple
|
||||||
except ZeroDivisionError:
|
print("Cette ligne ne sera jamais exécutée.")
|
||||||
pass
|
except ZeroDivisionError: # Ici, on intercepte spécifiquement le type d'erreur produit par la division
|
||||||
|
print("Le résultat n'a pas pu être calculé.")
|
||||||
|
|
||||||
|
print("Fin du programme.")
|
||||||
```
|
```
|
||||||
|
|
||||||
Gestion des erreurs de division par zéro
|
Gestion des erreurs de division par zéro
|
||||||
@ -39,30 +49,32 @@ Gestion des erreurs de division par zéro
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### À ne pas faire
|
### Mauvaise pratique sur les exceptions
|
||||||
|
|
||||||
Il est déconseillé d'utiliser directement la classe `Exception` (ou rien, d'ailleurs) avec la clause `except`;
|
Il est **ardemment** déconseillé d'utiliser directement la classe `Exception`{.python} (ou ne rien préciser, d'ailleurs) avec la clause `except`{.python};
|
||||||
ceci a pour effet de pousser votre code à réagir exactement de la même manière pour tous les cas de figure.
|
une clause trop générique intercepte **tous** les problèmes rencontrés dans le bloc `try`{.python}.
|
||||||
Si vous le tentez malgré tout, affichez ou conservez le traceback, vous me remercierez plus tard :
|
Dans certains cas, cela vous fera manquer des erreurs que vous ne souhaitez pas traiter avec le même bloc `except`{.python}.
|
||||||
|
|
||||||
```{.python .numberLines}
|
Une règle d'or de Python indique que dans le cas où vous masquez tous les types d'exception sans distinction, vous
|
||||||
|
ne devez jamais le faire silencieusement; affichez le problème ou consignez-le quelque part :
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print(15 / 0)
|
print(15 / 0)
|
||||||
except Exception: # ou except:
|
except Exception: # ou except:
|
||||||
traceback.print_exc() # Affiche le traceback dans la console
|
traceback.print_exc() # Affiche le traceback dans la console sans planter
|
||||||
```
|
```
|
||||||
|
|
||||||
Voir [antipattern sur les exceptions pour plus d'info](https://realpython.com/the-most-diabolical-python-antipattern/)
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### Un bloc `except`, plusieurs exceptions
|
### Un bloc `except`, plusieurs exceptions
|
||||||
|
|
||||||
On peut même avoir des blocs `except`{.python} prenant en charge plusieurs types d'exceptions, pour cela il suffit de les indiquer dans un tuple :
|
On peut même avoir des blocs `except`{.python} prenant en charge plusieurs types d'exceptions, pour cela il suffit d'indiquer
|
||||||
|
un tuple de classes d'exceptions à la clause `except`{.python} :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
try:
|
try:
|
||||||
pass # ou faire autre chose
|
pass # ou faire autre chose
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
@ -76,7 +88,7 @@ except (TypeError, ValueError):
|
|||||||
On peut, à l'instar de la structure `if/elif/else`, faire suivre le bloc `try`{.python} de
|
On peut, à l'instar de la structure `if/elif/else`, faire suivre le bloc `try`{.python} de
|
||||||
plusieurs blocs `except`{.python} :
|
plusieurs blocs `except`{.python} :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
try:
|
try:
|
||||||
print("Code à essayer")
|
print("Code à essayer")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -85,15 +97,20 @@ except TypeError:
|
|||||||
print("Code pour TypeError")
|
print("Code pour TypeError")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Python évaluera la structure de haut en bas. Si une erreur se produit dans le bloc `try`{.python},
|
||||||
|
Python évaluera d'abord le premier bloc `except`{.python}, de la même manière que pour toutes les structures de code.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Si aucun des blocs `except`{.python} ne gère précisément l'erreur qui se produit dans le bloc `try`{.python},
|
Si aucun des blocs `except`{.python} ne gère précisément l'erreur qui se produit dans le bloc `try`{.python},
|
||||||
alors l'interpréteur Python plante avec un traceback dans la console, comme attendu.
|
alors l'interpréteur Python plante avec un traceback dans la console, comme attendu.
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
try:
|
try:
|
||||||
1 / 0
|
1 / 0
|
||||||
except NameError:
|
except TypeError: # pas la bonne exception
|
||||||
|
pass
|
||||||
|
except NameError: # pas la bonne exception non plus
|
||||||
pass
|
pass
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -104,9 +121,9 @@ except NameError:
|
|||||||
La structure `try`{.python}...`except`{.python} peut être accompagnée d'un bloc `else`{.python}. Ce bloc
|
La structure `try`{.python}...`except`{.python} peut être accompagnée d'un bloc `else`{.python}. Ce bloc
|
||||||
sera exécuté si aucun des blocs `except`{.python} précédents n'a été exécuté (comme dans une structure `if`{.python}) :
|
sera exécuté si aucun des blocs `except`{.python} précédents n'a été exécuté (comme dans une structure `if`{.python}) :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
try:
|
try:
|
||||||
value = input("Saisissez un nombre entier :")
|
value = input("Saisissez un nombre entier : ")
|
||||||
value = int(value)
|
value = int(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
value = None
|
value = None
|
||||||
@ -121,7 +138,7 @@ else:
|
|||||||
|
|
||||||
Pour finir, il existe un bloc `finally`{.python}, dont le bloc est *toujours* exécuté, même si le programme doit planter :
|
Pour finir, il existe un bloc `finally`{.python}, dont le bloc est *toujours* exécuté, même si le programme doit planter :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
try:
|
try:
|
||||||
15 / 0
|
15 / 0
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -134,10 +151,12 @@ En général, on imagine l'utiliser lorsqu'on souhaite penser à toujours libér
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
On peut souhaiter également lever soi-même une exception pour notifier un problème à gérer.
|
### Lever une exception
|
||||||
C'est généralement le cas lorsque l'on fournit une API utilisable par d'autres développeurs.
|
|
||||||
|
|
||||||
```{.python .numberLines}
|
On peut souhaiter également lever soi-même une exception pour notifier un problème à gérer.
|
||||||
|
C'est généralement le cas lorsque l'on développe une bibliothèque utilisable par d'autres développeurs.
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
def do_something(value):
|
def do_something(value):
|
||||||
if not isinstance(value, int): # si value n'est pas un entier
|
if not isinstance(value, int): # si value n'est pas un entier
|
||||||
raise TypeError("Value must be an integer.")
|
raise TypeError("Value must be an integer.")
|
||||||
|
@ -9,7 +9,7 @@ author: Steve Kossouho
|
|||||||
|
|
||||||
## L'utilité des fonctions
|
## L'utilité des fonctions
|
||||||
|
|
||||||
Une fonction, c'est :
|
Le principe d'une fonction, c'est d'être :
|
||||||
|
|
||||||
1. Minimaliste si possible,
|
1. Minimaliste si possible,
|
||||||
2. Réutilisable,
|
2. Réutilisable,
|
||||||
@ -19,19 +19,23 @@ Une fonction, c'est :
|
|||||||
|
|
||||||
## Syntaxe de déclaration de fonctions
|
## Syntaxe de déclaration de fonctions
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def my_first_function():
|
def my_simple_function():
|
||||||
# Affiche un texte à chaque fois qu'on l'exécute
|
# Affiche un texte à chaque fois qu'on l'exécute
|
||||||
print("Voici le code de la fonction")
|
print("Bonjour, vous m'avez appelé ?")
|
||||||
|
print("Je suis une fonction très simple.")
|
||||||
my_first_function()
|
|
||||||
|
|
||||||
|
my_simple_function()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
La syntaxe permet de déclarer la fonction et dire à Python de lui associer du code.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Typographie des fonctions
|
## Typographie des fonctions
|
||||||
|
|
||||||
Les noms de fonctions se choisissent, par convention, comme toute autre variable :
|
Les noms de fonctions se choisissent, par **convention** (suivez les conventions), comme toute autre variable :
|
||||||
|
|
||||||
- Tout en minuscules (ex. `exponential`)
|
- Tout en minuscules (ex. `exponential`)
|
||||||
- Mots séparés par des underscores (ex. `get_warning_count`)
|
- Mots séparés par des underscores (ex. `get_warning_count`)
|
||||||
@ -41,9 +45,14 @@ Les noms de fonctions se choisissent, par convention, comme toute autre variable
|
|||||||
|
|
||||||
## Référence _versus_ appel de fonction
|
## Référence _versus_ appel de fonction
|
||||||
|
|
||||||
Lorsque vous définissez une fonction appelée `action` :
|
Lorsque vous déclarez une fonction appelée `action` :
|
||||||
|
|
||||||
`action` est une variable de type fonction dont vous pouvez ensuite exécuter le code associé.
|
```python {.numberLines}
|
||||||
|
def action():
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
`action` est une **variable** de type fonction dont vous pouvez ensuite exécuter le code associé.
|
||||||
|
|
||||||
- `action` est donc la référence de la fonction.
|
- `action` est donc la référence de la fonction.
|
||||||
- `action()`{.python} exécute le code de `action`, et récupère son expression de retour.
|
- `action()`{.python} exécute le code de `action`, et récupère son expression de retour.
|
||||||
@ -53,25 +62,26 @@ Lorsque vous définissez une fonction appelée `action` :
|
|||||||
## Valeurs de retour d'une fonction
|
## Valeurs de retour d'une fonction
|
||||||
|
|
||||||
En mathématiques, une fonction renvoie toujours une valeur.
|
En mathématiques, une fonction renvoie toujours une valeur.
|
||||||
Par exemple, on peut déclarer `Pour tout x dans les nombres réels, f(x) = x × 15`.
|
Par exemple, on peut déclarer `∀ x ∈ ℝ, f(x) = x × 15`{.latex}.
|
||||||
|
|
||||||
En Python, pour qu'une fonction qu'on déclare renvoie une valeur (transmette une valeur au code qui l'exécute)
|
En Python, pour qu'une fonction qu'on déclare renvoie une valeur (transmette une valeur au code qui l'exécute)
|
||||||
lorsqu'on l'exécute, il faut utiliser le mot-clé `return`{.python}.
|
lorsqu'on l'exécute, il faut utiliser le mot-clé `return`{.python}.
|
||||||
|
|
||||||
Lorsque le mot-clé est rencontré par l'interpréteur, il interrompt immédiatement l'exécution de la
|
Lorsque le mot-clé est rencontré par l'interpréteur, il interrompt immédiatement l'exécution de la
|
||||||
fonction et l'instruction qui a appelé la fonction récupère la valeur de l'expression qui a été retournée.
|
fonction et la valeur est transmise comme résultat de l'appel de la fonction.
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def multiply_by_five(value): # Fonction qui prend un argument nommé value
|
def squared(value):
|
||||||
return value * 5
|
# Renvoyer la valeur élevée au carré
|
||||||
|
return value ** 2.0
|
||||||
|
|
||||||
result = multiply_by_five(10) # l'expression `10 * 5` est assignée à la variable
|
result = squared(10) # on récupère 100
|
||||||
print(result) # affiche 50
|
print(result)
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### Valeurs de retour spécifiques
|
### Valeurs de retour et cas particuliers
|
||||||
|
|
||||||
Le mot-clé `return`{.python} a quelques comportements implicites :
|
Le mot-clé `return`{.python} a quelques comportements implicites :
|
||||||
|
|
||||||
@ -89,8 +99,8 @@ En clair, cela signifie qu'une fonction en Python renvoie **toujours** une valeu
|
|||||||
|
|
||||||
## Passer quelques arguments aux fonctions
|
## Passer quelques arguments aux fonctions
|
||||||
|
|
||||||
Déclarer une fonction simple, c'est déjà pas mal, mais en déclarer une qui dépend de un ou
|
Déclarer une fonction simple, c'est déjà pas mal, mais en déclarer une qui dépend d'un ou de
|
||||||
plusieurs arguments reçus en entrée, c'est bien plus utile !
|
plusieurs arguments reçus en entrée, c'est encore plus utile !
|
||||||
|
|
||||||
Python propose au moins 4 types d'arguments différents, dont les usages sont évidemment différents,
|
Python propose au moins 4 types d'arguments différents, dont les usages sont évidemment différents,
|
||||||
et parmi ceux-ci, deux sont absolument essentiels et nous allons les aborder :
|
et parmi ceux-ci, deux sont absolument essentiels et nous allons les aborder :
|
||||||
@ -104,7 +114,7 @@ et parmi ceux-ci, deux sont absolument essentiels et nous allons les aborder :
|
|||||||
|
|
||||||
Derrière cet adjectif un peu pompeux se cache le type d'argument le plus simple à déclarer et à utiliser :
|
Derrière cet adjectif un peu pompeux se cache le type d'argument le plus simple à déclarer et à utiliser :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def f(x, y):
|
def f(x, y):
|
||||||
# Accepte deux arguments, affiche leur valeur
|
# Accepte deux arguments, affiche leur valeur
|
||||||
# Mais ne renvoie rien d'autre que `None`
|
# Mais ne renvoie rien d'autre que `None`
|
||||||
@ -124,7 +134,7 @@ C'est de ce comportement que vient la notion de **positionnalité**.
|
|||||||
|
|
||||||
## Arguments : Valeurs par défaut
|
## Arguments : Valeurs par défaut
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def f(x, alpha=15, beta=16):
|
def f(x, alpha=15, beta=16):
|
||||||
# Accepte trois arguments, dont deux avec une valeur par défaut
|
# Accepte trois arguments, dont deux avec une valeur par défaut
|
||||||
print(x, alpha, beta)
|
print(x, alpha, beta)
|
||||||
@ -157,7 +167,7 @@ les arguments positionnels **doivent** être déclarés **en premier** dans la l
|
|||||||
Tous les arguments, positionnels (obligatoires) et par défaut, peuvent cependant être passés par leur nom,
|
Tous les arguments, positionnels (obligatoires) et par défaut, peuvent cependant être passés par leur nom,
|
||||||
mais ne faites jamais ça, vous induirez vos relecteurs en erreur :
|
mais ne faites jamais ça, vous induirez vos relecteurs en erreur :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def f(x, alpha=15, beta=16):
|
def f(x, alpha=15, beta=16):
|
||||||
return (x, alpha, beta) # renvoyer un tuple avec x, alpha et beta
|
return (x, alpha, beta) # renvoyer un tuple avec x, alpha et beta
|
||||||
|
|
||||||
@ -167,7 +177,7 @@ print(f(beta=23, x=50))
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Bonus : Argument "étoile" (séquence)
|
## Extra : Argument "étoile" (séquence)
|
||||||
|
|
||||||
Il existe un type d'argument, qui n'apparaît qu'une seule fois **maximum**, et dont le nom est précédé d'une étoile dans la signature de la fonction.
|
Il existe un type d'argument, qui n'apparaît qu'une seule fois **maximum**, et dont le nom est précédé d'une étoile dans la signature de la fonction.
|
||||||
|
|
||||||
@ -175,7 +185,7 @@ Cet argument apparaît après les arguments positionnels, et _de forte préfére
|
|||||||
Lors de l'exécution de la fonction, cet argument contient toujours un tuple valide, même vide.
|
Lors de l'exécution de la fonction, cet argument contient toujours un tuple valide, même vide.
|
||||||
Également, comme cet argument contient toujours un tuple, il est généralement nommé avec un nom **au pluriel**.
|
Également, comme cet argument contient toujours un tuple, il est généralement nommé avec un nom **au pluriel**.
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def stretchable(number, *words):
|
def stretchable(number, *words):
|
||||||
print(number, words) # words est toujours un tuple
|
print(number, words) # words est toujours un tuple
|
||||||
|
|
||||||
@ -188,49 +198,84 @@ stretchable(1) # le tuple `words` sera vide
|
|||||||
|
|
||||||
### Argument "étoile" : usage
|
### Argument "étoile" : usage
|
||||||
|
|
||||||
Un argument de ce type accepte, lors de l'appel de la fonction, un nombre de valeurs arbitraire (0 ou plus), et ces valeurs sont passées comme des arguments positionnels (sans nom d'argument).
|
Un argument de ce type accepte, lors de l'appel de la fonction,
|
||||||
|
un nombre de valeurs arbitraire (aucune ou plus), et ces valeurs sont passées comme des arguments positionnels
|
||||||
|
(sans nom d'argument).
|
||||||
|
|
||||||
Cette technique est utilisée dans la fonction `print`{.python} pour pouvoir afficher à la suite plusieurs arguments.
|
Cette technique est utilisée dans la fonction `print`{.python} pour pouvoir afficher à la suite plusieurs arguments.
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
|
from sys import stdout
|
||||||
|
|
||||||
|
def custom_print(*values):
|
||||||
|
for value in values:
|
||||||
|
stdout.write(value)
|
||||||
|
stdout.write(" ")
|
||||||
|
stdout.write("\n") # Échappement pour passer à la ligne
|
||||||
|
|
||||||
|
custom_print("Hello", "et", "bienvenue !")
|
||||||
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
On peut directement renseigner une liste pour ce type d'argument, en passant, lors de l'appel de fonction, une expression de liste (ou tuple) précédée par une étoile :
|
On peut directement renseigner une liste pour ce type d'argument, en passant, lors de l'appel de fonction,
|
||||||
|
une expression de _liste_ (ou _tuple_) précédée par une étoile :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def star_function(number, *words):
|
def function_with_extensible_args(number, *words):
|
||||||
print(number, words) # words est toujours une liste
|
print(number, words) # words est toujours une liste
|
||||||
|
|
||||||
star_function(15, *["word 1", "word 2", "word 3"]) # raccourci
|
|
||||||
```
|
|
||||||
|
|
||||||
TODO: Si arg étoile suivi de défaut, passer *[], suivi d'une valeur positionnelle, cette dernière s'ajoute quand même à l'argument étoile, et donc obligation passer l'argument par défaut via son nom.
|
|
||||||
|
function_with_extensible_args(15, *["word 1", "word 2", "word 3"], "word 4") # raccourci
|
||||||
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Bonus : Argument "double-étoile" (dictionnaire)
|
## Extra : Argument "double-étoile" (dictionnaire)
|
||||||
|
|
||||||
Un dernier type d'argument, apparaît aussi une seule fois **maximum**, et généralement en tout dernier dans les arguments. Celui-ci s'utilise en passant des noms d'arguments qui n'existent pas ailleurs dans la signature de la fonction :
|
Un dernier type d'argument, apparaît aussi une seule fois **maximum**, et généralement en tout dernier dans les arguments.
|
||||||
|
Celui-ci s'utilise en passant des noms d'arguments qui n'existent pas ailleurs dans la signature de la fonction :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def f_keywords(other=15, **kwargs):
|
from typing import Any
|
||||||
print(kwargs) # toujours un dictionnaire
|
|
||||||
|
def function_with_custom_named_args(other: Any = 15, **kwargs):
|
||||||
f_keywords(plop="Hello", foo=19) # vont dans le dictionnaire `kwargs`.
|
print(other, kwargs) # toujours un dictionnaire
|
||||||
|
|
||||||
|
|
||||||
|
function_with_custom_named_args(plop="Hello", foo=19) # vont dans le dictionnaire `kwargs`.
|
||||||
|
function_with_custom_named_args(other="Hello", tornado=19) # tornado ira dans le dictionnaire `kwargs`.
|
||||||
```
|
```
|
||||||
|
|
||||||
On appelle aussi cet argument l'argument "mots-clés", et s'appelle très fréquemment `kwargs`.
|
On appelle souvent cet argument l'argument [mots-clés]{.naming}, et s'appelle très fréquemment `kwargs` ou
|
||||||
|
`options`.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Si l'on appelle `f_keywords`{.python} avec un argument `plop`, Python regarde si un argument de ce nom existe. Si oui, la valeur de cet argument est modifiée. Si non, l'argument est ajouté comme association dans `kwargs`, de telle façon que `kwargs == {"plop": "Hello"}`{.python}.
|
### Fonctionnement de l'argument
|
||||||
|
|
||||||
Souvent utilisé par coquetterie, mais l'argument pourrait être généralement remplacé par le simple passage d'un dictionnaire dans un argument positionnel.
|
Si l'on appelle `function_with_custom_named_args`{.python} avec un argument `plop`, Python regarde si la fonction
|
||||||
|
accepte explicitement un argument de ce nom :
|
||||||
|
|
||||||
|
- Si oui, l'argument prendra cette valeur.
|
||||||
|
- Si non, l'argument est ajouté comme association dans `kwargs`, de telle façon que `kwargs == {"plop": "Hello"}`{.python}.
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
|
def function_with_custom_named_args(other=15, **kwargs):
|
||||||
|
print(other, kwargs) # toujours un dictionnaire
|
||||||
|
|
||||||
|
|
||||||
|
function_with_custom_named_args(plop="Hello")
|
||||||
|
```
|
||||||
|
|
||||||
|
L'argument est de plus en plus rarement utilisé, sauf par des bibliothèques qui ont besoin d'accepter des noms
|
||||||
|
calculés dynamiquement pour fonctionner.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Arguments : Ordre de déclaration
|
## Arguments : Ordre de déclaration
|
||||||
|
|
||||||
Si vous deviez avoir dans vos fonctions tous les types d'arguments que nous avons vus, l'ordre de leur
|
Si vous deviez avoir dans la déclaration de vos fonctions tous les types d'arguments que nous avons vus, l'ordre de leur
|
||||||
apparition **devrait** être le suivant :
|
apparition **devrait** être le suivant :
|
||||||
|
|
||||||
1. `positionnel` (toujours premier)
|
1. `positionnel` (toujours premier)
|
||||||
@ -252,7 +297,7 @@ simplement nommé `/`{.python}. Il ne peut exister qu'une fois au maximum.
|
|||||||
Lorsque vous spécifiez cet argument dans votre signature, **tous les arguments qui le précèdent ne
|
Lorsque vous spécifiez cet argument dans votre signature, **tous les arguments qui le précèdent ne
|
||||||
peuvent pas être spécifiés autrement que positionnellement** :
|
peuvent pas être spécifiés autrement que positionnellement** :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def my_function(a, b, /, c, d):
|
def my_function(a, b, /, c, d):
|
||||||
print(a, b, c, d)
|
print(a, b, c, d)
|
||||||
|
|
||||||
@ -261,7 +306,7 @@ my_function(1, 2, c=3, d=4) # autorisé
|
|||||||
my_function(1, b=2, c=3, d=4) # impossible, b est positionnel uniquement
|
my_function(1, b=2, c=3, d=4) # impossible, b est positionnel uniquement
|
||||||
```
|
```
|
||||||
|
|
||||||
Lorsqu'un argument `/`{.python} ou `*`{.python} est présent, les arguments `*args`{.python} sont interdits. La raison est que, si un tel
|
Lorsqu'un argument `/`{.python} est présent, les arguments `*args`{.python} sont interdits. La raison est que, si un tel
|
||||||
argument est présent, on est automatiquement tenu de passer les arguments qui suivent par leur nom.
|
argument est présent, on est automatiquement tenu de passer les arguments qui suivent par leur nom.
|
||||||
|
|
||||||
----
|
----
|
||||||
@ -269,13 +314,13 @@ argument est présent, on est automatiquement tenu de passer les arguments qui s
|
|||||||
### Arguments spéciaux : Étoile
|
### Arguments spéciaux : Étoile
|
||||||
|
|
||||||
Vous pouvez contrôler l'utilisation de vos fonctions en ajoutant dans votre signature un argument
|
Vous pouvez contrôler l'utilisation de vos fonctions en ajoutant dans votre signature un argument
|
||||||
simplement nommé `*`{.python}. Il ne peut exister qu'une fois au maximum, et se trouver après l'argument
|
simplement marqué `*`{.python}. Il ne peut exister qu'une fois au maximum, et se trouver après l'argument
|
||||||
`/`{.python}.
|
`/`{.python}.
|
||||||
|
|
||||||
Lorsque vous spécifiez cet argument dans votre signature, **tous les arguments qui le suivent ne
|
Lorsque vous spécifiez cet argument dans votre signature, **tous les arguments qui le suivent ne
|
||||||
peuvent être spécifiés autrement qu'en précisant leur nom** :
|
peuvent être spécifiés autrement qu'en précisant leur nom** :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def my_function(a, b, c=3, *, d=4):
|
def my_function(a, b, c=3, *, d=4):
|
||||||
print(a, b, c, d)
|
print(a, b, c, d)
|
||||||
|
|
||||||
|
@ -7,8 +7,9 @@ author: Steve Kossouho
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
En Python, on peut écrire des choses simples avec un seul script. Mais
|
En Python, on peut écrire des choses simples qui tiennent dans un seul fichier de script.
|
||||||
souvent, et même pour des choses simples, on peut se retrouver à écrire du code, organisé de façon un peu plus complexe, ou même du code qui réutilise des fonctionnalités en dehors de votre script.
|
Souvent, les projets plus ambitieux écrivent du code organisé de façon un peu plus complexe,
|
||||||
|
ou encore du code qui réemploie des fonctionnalités décrites dans des scripts externes.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -16,7 +17,9 @@ souvent, et même pour des choses simples, on peut se retrouver à écrire du co
|
|||||||
|
|
||||||
Jusque là, tout ce que nous avons écrit, c'est des [modules]{.naming}. Ce sont des fichiers .py (vides ou non, ils peuvent contenir du code).
|
Jusque là, tout ce que nous avons écrit, c'est des [modules]{.naming}. Ce sont des fichiers .py (vides ou non, ils peuvent contenir du code).
|
||||||
|
|
||||||
Il existe aussi les [packages]{.naming}. Ce sont des répertoires, pouvant contenir d'autres modules, et qui sont utilisables comme des modules (peuvent contenir du code). Pour pouvoir associer du code à ces répertoires et les considérer comme des packages, le langage Python impose que le code associé repose dans un fichier nommé `__init__.py` dans le répertoire. L'intérêt principal d'un package est d'y ranger d'autres packages et modules, pour organiser son code en arborescence cohérente.
|
Il existe aussi les [packages]{.naming}. Ce sont des répertoires, pouvant contenir d'autres modules, et qui sont utilisables comme des modules (peuvent contenir du code).
|
||||||
|
Pour pouvoir associer du code à ces répertoires et les considérer comme des packages, la spécification du langage Python impose que le code associé repose dans un
|
||||||
|
fichier nommé `__init__.py` dans le répertoire. L'intérêt principal d'un package est d'y ranger d'autres packages et modules, pour organiser son code en arborescence cohérente.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -24,9 +27,10 @@ Il existe aussi les [packages]{.naming}. Ce sont des répertoires, pouvant conte
|
|||||||
|
|
||||||
Les modules et packages ont la même typographie que les variables (car Python les traite comme des variables de type `module`) :
|
Les modules et packages ont la même typographie que les variables (car Python les traite comme des variables de type `module`) :
|
||||||
|
|
||||||
- Tout en minuscules (ex. `mypackage`)
|
- Tout en minuscules (ex. `my_package`)
|
||||||
- <span style="color:red;">Sans espace ni tiret</span> (ex. `my_package`)
|
- Sans espace ni tiret (ex. `super_package`). Un module contenant un espace n'est pas réutilisable.
|
||||||
- etc.
|
- Aucun caractère accentué (ex. `derogations_generiques`)
|
||||||
|
- Peut contenir des chiffres, mais doit commencer par une lettre.
|
||||||
|
|
||||||
|
|
||||||
----
|
----
|
||||||
@ -37,87 +41,135 @@ Python est à la fois un langage et un exécutable interprétant des scripts éc
|
|||||||
L'interpréteur est toujours livré avec ce qu'on appelle la bibliothèque standard.
|
L'interpréteur est toujours livré avec ce qu'on appelle la bibliothèque standard.
|
||||||
Il s'agit d'une immense bibliothèque de fonctionnalités, que l'on peut réutiliser dans nos programmes.
|
Il s'agit d'une immense bibliothèque de fonctionnalités, que l'on peut réutiliser dans nos programmes.
|
||||||
|
|
||||||
La bibliothèque propose des outils pour manipuler du texte, du réseau, des bases de données, des fonctions mathématiques etc.
|
La bibliothèque propose des outils pour manipuler du texte, du réseau, des bases de données, des fonctions mathématiques, etc.
|
||||||
|
|
||||||
[Liste des modules et packages de la bibliothèque standard](https://docs.python.org/3/library/)
|
[Liste des modules et packages de la bibliothèque standard](https://docs.python.org/3/library/)
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Parmi les très nombreux modules de la bibliothèque standard, assez peu vous serviront régulièrement. En voici une liste :
|
### Modules utiles
|
||||||
|
|
||||||
|
Parmi les très nombreux modules (environ `220`) de la bibliothèque standard, assez peu vous serviront régulièrement.
|
||||||
|
En voici une liste :
|
||||||
|
|
||||||
- `random` : génération de nombres aléatoires
|
- `random` : génération de nombres aléatoires
|
||||||
- `math` : fonctions mathématiques et trigonométriques
|
- `math` : fonctions arithmétiques, logarithmiques et trigonométriques
|
||||||
- `statistics` : fonctions statistiques, comme l'écart type.
|
- `statistics` : fonctions statistiques de base, comme l'écart type.
|
||||||
- `pathlib` : outils pour gérer les chemins de fichier
|
- `pathlib` : outils pour gérer les chemins de fichier
|
||||||
- `datetime` : types pour gérer les dates
|
- `datetime` : types pour gérer les dates
|
||||||
|
- `re` : pour gérer des expressions régulières (compatibles _Perl_)
|
||||||
|
|
||||||
D'autres peuvent servir ponctuellement, comme `csv` ou `sqlite3` pour nos exemples à venir.
|
D'autres peuvent servir ponctuellement, comme `csv` ou `sqlite3` pour nos exemples à venir.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Comment accéder à ces nombreuses fonctionnalités ?
|
### Importer des fonctionnalités
|
||||||
Par défaut, elles ne sont pas toutes accessibles dans votre code, excepté celles documentées dans les sections "built-in", et pour pouvoir les utiliser, il faut en faire la demande explicite dans vos modules via la notion d'`import` :
|
|
||||||
|
|
||||||
Variantes :
|
Par défaut, seules les fonctionnalités documentées dans les sections natives (`builtins`) sont directement utilisables,
|
||||||
|
et pour pouvoir utiliser les autres fonctionnalités, il faut en faire la demande explicite dans votre code via la notion d'`import` :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
# Les imports sont écrits au sommet d'un module
|
import math # importe le module math via une variable
|
||||||
import math # vous avez maintenant une variable nommée `math`
|
from os import path # importe le module path du package os
|
||||||
from os import path # vous avez une variable `path`
|
from os.path import basename # importe directement basename depuis os.path
|
||||||
|
from math import sin, cos # importer plusieurs fonctions depuis math
|
||||||
import datetime as dt # datetime est utilisable en tant que dt uniquement
|
import datetime as dt # datetime est utilisable en tant que dt uniquement
|
||||||
|
|
||||||
from math import sin, cos # importer plusieurs fonctions de la même bibliothèque
|
print(math.cos(math.pi / 2.0)) # utilise uniquement l'import de math
|
||||||
|
print(cos(math.pi / 2.0), sin(math.pi / 2.0)) # utilise l'import de sin et cos
|
||||||
math.cos(math.pi / 2.0) # possible grâce à import math
|
print(path.basename("/chemin/de/fichier/linux.txt")) # utilise l'import de path
|
||||||
cos(0) # possible grâce à from math import cos
|
print(basename("/chemin/de/fichier/linux.txt")) # utilise l'import de basename
|
||||||
path.join(…)
|
print(dt.date.today())
|
||||||
```
|
```
|
||||||
|
|
||||||
Chaque script qui utilise directement un _symbole_ doit toujours l'importer.
|
Chaque script qui référence directement un objet provenant d'une bibliothèque doit toujours l'importer.
|
||||||
|
|
||||||
**Note** : Pour importer le contenu d'un module, l'interpréteur Python doit toujours exécuter le contenu dudit module, afin d'en connaître le contenu. Attention donc à la présence de `print` dans ledit module.
|
**Note** : Pour importer le contenu d'un module ou un élément d'un module, l'interpréteur Python doit toujours
|
||||||
|
exécuter le contenu dudit module, afin d'en connaître le contenu.
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Note : Normalement, importer un package donne accès uniquement aux variables directement définies dans celui-ci, mais pas
|
## Un peu de calcul avec la bibliothèque standard
|
||||||
aux sous-modules ou packages qui s'y trouvent. Si vous créez un package `package` contenant un sous-module `module1` :
|
|
||||||
|
|
||||||
```{.python .numberLines}
|
|
||||||
import package
|
|
||||||
|
|
||||||
print(package.module1) # ceci provoque une erreur
|
|
||||||
```
|
|
||||||
|
|
||||||
Cela ne fonctionne pas car Python ne charge pas directement les modules et packages présents à l'intérieur du package.
|
|
||||||
Pour y avoir accès, il faut que le package lui-même importe les éléments qui seront directement accessibles depuis celui-ci :
|
|
||||||
|
|
||||||
```{.python .numberLines}
|
|
||||||
from . import module1 # ajoute une variable module1 dans le package
|
|
||||||
```
|
|
||||||
`package/__init__.py`
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Faire un petit peu de calcul avec la bibliothèque standard
|
|
||||||
|
|
||||||
Avec l'outil que sont les imports, on peut avoir accès à de nombreuses fonctions de calcul.
|
Avec l'outil que sont les imports, on peut avoir accès à de nombreuses fonctions de calcul.
|
||||||
Par exemple, on pourrait générer un nombre aléatoire et calculer un cosinus :
|
Par exemple, on pourrait générer un nombre aléatoire et calculer un cosinus :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
import random
|
import random
|
||||||
import math
|
import math
|
||||||
|
|
||||||
random_number = random.randint(0, 100) # nombre entre 0 et 100 inclus
|
number = random.randint(0, 100) # nombre entre 0 et 100 inclus
|
||||||
cosinus_result = math.cos(random_number) # cosinus du nombre aléatoire
|
cosinus_result = math.cos(number) # cosinus du nombre aléatoire
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
guess = int(input("Saisissez un nombre entre 0 et 100 : "))
|
||||||
|
# Les lignes suivantes s'exécuteront si la ligne du dessus ne génère pas d'erreur
|
||||||
|
if guess < number:
|
||||||
|
print("C'est supérieur.")
|
||||||
|
elif guess > number:
|
||||||
|
print("C'est inférieur.")
|
||||||
|
else:
|
||||||
|
print("C'est gagné !")
|
||||||
|
break # Quitter la boucle
|
||||||
|
except ValueError: # si impossible de récupérer l'équivalent entier
|
||||||
|
print("Saisie incorrecte.")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- [Documentation du module `random`](https://docs.python.org/3/library/random.html)
|
||||||
|
- [Documentation du module `math`](https://docs.python.org/3/library/math.html)
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Bonus : Installer des paquets externes ([PyPI](https://pypi.org))
|
## Extra : Installer des paquets externes ([PyPI](https://pypi.org))
|
||||||
|
|
||||||
Avec PyCharm, on va installer simplement quelques paquets externes et utiliser leurs fonctionnalités :
|
Avec PyCharm, on peut installer simplement quelques paquets externes et utiliser leurs fonctionnalités :
|
||||||
|
|
||||||
1. `requests` : Faire des requêtes HTTP plus simplement
|
1. `requests` : Faire des requêtes HTTP et consommer des API REST
|
||||||
2. `unidecode` : Translittération et désaccentuation
|
2. `unidecode` : Translittération et désaccentuation
|
||||||
3. `attrs` : Accélérer l'écriture de classes
|
3. `faker` : Anonymiser avec des données factices (noms, adresses, téléphone, code pin, etc.)
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
### Gérer un environnement virtuel pour installer des bibliothèques
|
||||||
|
|
||||||
|
Python est livré avec un outil en ligne de commande nommé `pip`, qui vous permet facilement de télécharger et
|
||||||
|
installer des bibliothèques externes publiées sur le site [PyPI](https://pypi.org).
|
||||||
|
|
||||||
|
Si pour votre projet, vous avez besoin de la dernière version de la bibliothèque `requests`, par exemple, vous pouvez l'installer
|
||||||
|
avec la commande suivante dans un terminal :
|
||||||
|
|
||||||
|
```sh {.numberLines}
|
||||||
|
pip install requests
|
||||||
|
```
|
||||||
|
|
||||||
|
La dernière version de la bibliothèque compatible avec votre version de Python sera installée dans un répertoire spécifique
|
||||||
|
avec le nom `requests`. Vous ne pouvez pas installer plusieurs versions simultanées de la même bibliothèque au même endroit.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
### Les environnements virtuels pour gérer ses versions de paquets
|
||||||
|
|
||||||
|
Un environnement virtuel (`venv`) se présente sous la forme d'un répertoire avec quelques scripts, dont `python`. Lorsqu'un environnement
|
||||||
|
virtuel est "activé" via l'un de ses scripts, il se passe plusieurs choses :
|
||||||
|
|
||||||
|
- Les bibliothèques installées avec `pip` sont installées dans cet environnement virtuel
|
||||||
|
- L'exécutable `python` de l'environnement peut importer les bibliothèques installées dans ce dernier
|
||||||
|
|
||||||
|
L'intérêt est de pouvoir facilement gérer plusieurs projets qui nécessitent des versions différentes des mêmes
|
||||||
|
bibliothèques.
|
||||||
|
|
||||||
|
Les environnements virtuels peuvent être créés, sélectionnés, et utilisés automatiquement avec Visual Studio Code
|
||||||
|
et PyCharm.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
#### PyCharm
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
#### Visual Studio Code
|
||||||
|
|
||||||
|
TODO
|
||||||
|
@ -96,7 +96,7 @@ Tout ce qu'on a d'utile, c'est :
|
|||||||
|
|
||||||
Une bibliothèque externe Python propose des outils pour effectuer certaines de ces actions :
|
Une bibliothèque externe Python propose des outils pour effectuer certaines de ces actions :
|
||||||
|
|
||||||
```bash {.numberLines}
|
```sh {.numberLines}
|
||||||
pip install textfile
|
pip install textfile
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ source ./activate # ou activate.csh ou activate.fish
|
|||||||
|
|
||||||
Sous Windows, vous devez plutôt simplement exécuter une commande :
|
Sous Windows, vous devez plutôt simplement exécuter une commande :
|
||||||
|
|
||||||
```bash {.numberLines}
|
```sh {.numberLines}
|
||||||
./scripts/activate.ps1 # Dans le powershell si vous êtes dans le répertoire du venv
|
./scripts/activate.ps1 # Dans le powershell si vous êtes dans le répertoire du venv
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -57,11 +57,11 @@ pour les créer, en observant quelques précautions :
|
|||||||
Si vous souhaitez installer des paquets qui sont (avec leurs dépendances) disponibles dans un répertoire local avec `pip`, que ce
|
Si vous souhaitez installer des paquets qui sont (avec leurs dépendances) disponibles dans un répertoire local avec `pip`, que ce
|
||||||
soit via un fichier `requirements.txt` ou manuellement, vous devez utiliser l'une des commandes suivantes (les options sont les plus importantes) :
|
soit via un fichier `requirements.txt` ou manuellement, vous devez utiliser l'une des commandes suivantes (les options sont les plus importantes) :
|
||||||
|
|
||||||
```bash {.numberLines}
|
```sh {.numberLines}
|
||||||
pip install -r requirements.txt --no-index --find-links=<répertoire>
|
pip install -r requirements.txt --no-index --find-links=<répertoire>
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash {.numberLines}
|
```sh {.numberLines}
|
||||||
pip install <fichier .whl> --no-index --find-links=<répertoire>
|
pip install <fichier .whl> --no-index --find-links=<répertoire>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
BIN
documentation/assets/images/basics-sets-hash-table.png
Normal file
BIN
documentation/assets/images/basics-sets-hash-table.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 369 KiB |
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
## Reçu d'achat
|
||||||
|
|
||||||
Vous avez devant vous un adhérent de la librairie.
|
Vous avez devant vous un adhérent de la librairie.
|
||||||
Il souhaite acheter 3 livres :
|
Il souhaite acheter 3 livres :
|
||||||
|
|
||||||
@ -10,13 +12,13 @@ Il souhaite acheter 3 livres :
|
|||||||
- Guide de Sao Paulo (12,00€)
|
- Guide de Sao Paulo (12,00€)
|
||||||
|
|
||||||
Le livre Python pour les débutants bénéficie d'une réduction de 20% sur son prix.
|
Le livre Python pour les débutants bénéficie d'une réduction de 20% sur son prix.
|
||||||
Affichez un récapitulatif du reçu d'achat en stockant dans des variables les titres
|
Affichez un récapitulatif du reçu d'achat **en stockant dans des variables les titres
|
||||||
des livres et leurs prix.
|
des livres et leurs prix**.
|
||||||
|
|
||||||
Le reçu peut ressembler à cela :
|
Le reçu peut ressembler à cela :
|
||||||
|
|
||||||
```
|
```
|
||||||
Bookie Dans SAS
|
Librairie des Recollets
|
||||||
|
|
||||||
Reçu
|
Reçu
|
||||||
- La fable du marronnier 19.95
|
- La fable du marronnier 19.95
|
||||||
@ -28,3 +30,32 @@ Réduction
|
|||||||
Total
|
Total
|
||||||
<calculez la valeur>
|
<calculez la valeur>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Minutes et secondes
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Critical content comes here.
|
||||||
|
|
||||||
|
|
||||||
|
Vous lancez une simulation complexe, qui vous prend beaucoup de temps. Quand elle se termine,
|
||||||
|
vous récupérez une valeur indiquant le nombre de secondes nécessaires à son exécution.
|
||||||
|
|
||||||
|
Vous récupérez la valeur `867`{.python}.
|
||||||
|
|
||||||
|
Affichez le nombre de minutes et de secondes nécessaires à l'exécution de cette tâche,
|
||||||
|
à savoir `14` minutes et `27` secondes. Vous avez besoin de deux opérateurs arithmétiques pour obtenir
|
||||||
|
le résultat attendu.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Heures, minutes et secondes
|
||||||
|
|
||||||
|
(_Voir exercice précédent_) Cette fois-ci, vous récupérez suite à la simulation un nombre encore
|
||||||
|
plus élevé, `4377`{.python}.
|
||||||
|
|
||||||
|
Affichez cette fois-ci le nombre d'heures, de minutes et de secondes nécessaires à l'exécution
|
||||||
|
de cette tâche. Vous devriez obtenir `1` heure, `12` minutes et `57` secondes.
|
||||||
|
|
||||||
|
----
|
||||||
|
Reference in New Issue
Block a user