1670 lines
23 KiB
Markdown
1670 lines
23 KiB
Markdown
# Python
|
||
|
||
notes:
|
||
|
||
Juste pour le doctest :
|
||
|
||
```python
|
||
import random
|
||
random.seed(42)
|
||
|
||
ingredients = ["sel", "farine", "sucre", "levure", "beurre", "œuf"]
|
||
|
||
def randint(a, b):
|
||
return 4 # https://xkcd.com/221/
|
||
|
||
il_reste_de_la_pâte = 0
|
||
|
||
recettes = [
|
||
{'titre': 'Broyés du Poitou', 'ingredients': "farine", "durée": 35},
|
||
{'titre': 'Œufs mimosa', 'ingredients': "", "durée": 20},
|
||
{'titre': 'Houmous', 'ingredients': "", "durée": 13},
|
||
]
|
||
```
|
||
|
||
|
||
## Python
|
||
|
||
par
|
||
|
||
Julien Palard <julien@palard.fr>
|
||
|
||
https://mdk.fr
|
||
|
||
notes:
|
||
|
||
Introduce yourself!
|
||
|
||
Ça couvre les types de bases survol quelques strucutres de contrôle,
|
||
et quelques fonctions natives.
|
||
|
||
|
||
## Python : Introduction
|
||
|
||
Python est un langage de programmation permettant de s'exprimer de
|
||
manière **concise** et **lisible**.
|
||
|
||
|
||
## Qui utilise Python ?
|
||
|
||
YouTube, Dropbox, Reddit, Instagram, Spotify, NASA…
|
||
|
||
![](static/Black-hole-M87.jpg)
|
||
|
||
|
||
## Combien utilisent Python ?
|
||
|
||
![](static/Evolution_of_Python.png)
|
||
|
||
::: notes
|
||
|
||
https://insights.stackoverflow.com/trends
|
||
|
||
|
||
## Installation
|
||
|
||
https://python.org
|
||
|
||
— ou —
|
||
|
||
![](static/Anaconda_Logo.png)
|
||
|
||
|
||
::: notes
|
||
|
||
- On windows use the WSL, or gitforwindows.org if you can't
|
||
- https://docs.python.org/3/using/windows.html
|
||
- https://docs.python.org/3/using/mac.html
|
||
- On windows, don't install from the Microsoft Store.
|
||
|
||
|
||
## Démarrer un interpréteur
|
||
|
||
Sur Windows :
|
||
|
||
```text
|
||
py
|
||
```
|
||
|
||
Sur tous les autres OS :
|
||
|
||
```text
|
||
python3
|
||
```
|
||
|
||
::: notes
|
||
|
||
- Définir « Interpréteur »
|
||
- `py` sur Windows trouve l'interpréteur le plus récent.
|
||
|
||
|
||
## L'interpréteur
|
||
|
||
Parfois appelé le *REPL* ou *la console interactive*.
|
||
|
||
```bash
|
||
$ python3
|
||
>>> 5 + 2
|
||
7
|
||
>>>
|
||
```
|
||
|
||
notes:
|
||
|
||
Permet d'essayer un peu de Python sans pour autant ouvrir un fichier.
|
||
|
||
Et oui, même après 10 ans de Python, on l'utilise encore.
|
||
|
||
Expliquer les parties "R", "E", "P", "L".
|
||
|
||
|
||
## L'interpréteur
|
||
|
||
Il en existe plusieurs : Celui natif à Python, IDLE, IPython, …
|
||
|
||
Il ressemble généralement soit à ça :
|
||
|
||
```bash
|
||
>>>
|
||
```
|
||
soit à ça :
|
||
```bash
|
||
In [1]:
|
||
```
|
||
|
||
|
||
## Testons l'interpréteur
|
||
|
||
```pycon
|
||
>>> 10
|
||
10
|
||
```
|
||
|
||
notes:
|
||
|
||
L'interpréteur à lu les caractères `1` `0`, a compris que c'était un
|
||
nombre entier, l'a stocké dans sa représentation interne, un objet,
|
||
puis nous l'a représenté à son tour avec deux caractères `1` et `0`
|
||
pour qu'on puisse le lire.
|
||
|
||
|
||
## C'est votre nouvelle calculatrice
|
||
|
||
```pycon
|
||
>>> 60 * 60 * 4
|
||
14400
|
||
```
|
||
|
||
|
||
## Les exceptions
|
||
|
||
```pycon
|
||
>>> 5 / 0
|
||
Traceback (most recent call last):
|
||
File "<stdin>", line 1, in <module>
|
||
ZeroDivisionError: division by zero
|
||
```
|
||
|
||
notes:
|
||
|
||
Lisez *TOUJOURS* la dernière ligne en premier !
|
||
|
||
|
||
# Types natifs
|
||
|
||
## Booléens
|
||
|
||
```pycon
|
||
>>> True
|
||
True
|
||
>>> False
|
||
False
|
||
```
|
||
|
||
|
||
|
||
## Nombres
|
||
|
||
```pycon
|
||
>>> 42
|
||
42
|
||
```
|
||
|
||
|
||
## Nombres
|
||
|
||
```pycon
|
||
>>> 18446744073709551616
|
||
18446744073709551616
|
||
```
|
||
|
||
|
||
## Nombres
|
||
|
||
```pycon
|
||
>>> 3.1415
|
||
3.1415
|
||
```
|
||
|
||
|
||
## Chaînes de caractères
|
||
|
||
```pycon
|
||
>>> "Beurre ou huile d'olive ?"
|
||
"Beurre ou huile d'olive ?"
|
||
```
|
||
|
||
notes:
|
||
|
||
Expliquer ce qu'est une chaîne, sans parler de pointeurs, on est pas
|
||
dans un cours de C89.
|
||
|
||
|
||
## Chaînes de caractères
|
||
|
||
```pycon
|
||
>>> 'Cuisson "au beurre" !!'
|
||
'Cuisson "au beurre" !!'
|
||
```
|
||
|
||
notes:
|
||
|
||
Les triples quotes apparaissent jour 2.
|
||
|
||
|
||
## Listes
|
||
|
||
```pycon
|
||
>>> ["1 kg de farine", "12 œufs", "130 g de beurre"]
|
||
['1 kg de farine', '12 œufs', '130 g de beurre']
|
||
```
|
||
|
||
notes:
|
||
|
||
La représentation est souvent du Python valide.
|
||
|
||
|
||
## Listes
|
||
|
||
```pycon
|
||
>>> ["farine", 1000]
|
||
['farine', 1000]
|
||
```
|
||
|
||
notes:
|
||
|
||
Attention à ne pas abuser du mélange autorisé des types.
|
||
|
||
|
||
## *n*-uplets, *tuple*
|
||
|
||
```pycon
|
||
>>> ("œufs", 12)
|
||
('œufs', 12)
|
||
>>> ("sucre", 130)
|
||
('sucre', 130)
|
||
```
|
||
|
||
notes:
|
||
|
||
C'est la virgule qui fait le n-uplet, pas les parenthèses.
|
||
|
||
Pensez au *n*-uplet comme une structure C, *a record*, pas comme une
|
||
liste, par exemple des coordonnées : (x, y).
|
||
|
||
|
||
## Listes et tuples
|
||
|
||
```pycon
|
||
>>> [("farine", 1000), ("œufs", 12), ("sucre", 130)]
|
||
[('farine', 1000), ('œufs', 12), ('sucre', 130)]
|
||
```
|
||
|
||
notes:
|
||
|
||
Une liste c'est de la donnée, ce qu'elle contint c'est de la donnée.
|
||
|
||
|
||
## Ensembles
|
||
|
||
```python
|
||
{"farine", "sucre", "œuf", "levure", "sel", "beurre"}
|
||
```
|
||
|
||
notes:
|
||
|
||
Un ensemble n'est pas ordonné.
|
||
|
||
|
||
## Dictionnaires
|
||
|
||
```python
|
||
{
|
||
"un verre": "25 cl",
|
||
"un petit verre": "12 cl",
|
||
"qs": "quantité suffisante"
|
||
}
|
||
```
|
||
|
||
notes:
|
||
|
||
On associe une valeur à une clé. Utile *seulement* si on ne connaît
|
||
pas les clefs à l'avance, sinon c'est une classe.
|
||
|
||
|
||
# Les opérateurs
|
||
|
||
## Les opérateurs mathématiques
|
||
|
||
```pycon
|
||
>>> 10 + 10
|
||
20
|
||
>>> 10.5 + 2
|
||
12.5
|
||
```
|
||
|
||
|
||
## Les opérateurs mathématiques
|
||
|
||
```pycon
|
||
>>> (4 * 10**1) + (2 * 10**0)
|
||
42
|
||
```
|
||
|
||
## Les opérateurs mathématiques
|
||
|
||
```pycon
|
||
>>> 10 / 2
|
||
5.0
|
||
```
|
||
|
||
## Les opérateurs
|
||
|
||
|
||
```pycon
|
||
>>> "Bri" + "oche"
|
||
'Brioche'
|
||
```
|
||
|
||
notes:
|
||
|
||
It's called concatenation of strings.
|
||
|
||
|
||
## Les opérateurs
|
||
|
||
```pycon
|
||
>>> "mur" * 2
|
||
'murmur'
|
||
```
|
||
|
||
notes:
|
||
|
||
Tant qu'il n'y a pas d'ambiguité, c'est implémenté.
|
||
|
||
|
||
## Les opérateurs
|
||
|
||
```pycon
|
||
>>> ["farine", "œufs"] + ["sucre", "sel"]
|
||
['farine', 'œufs', 'sucre', 'sel']
|
||
```
|
||
|
||
|
||
## Les Comparisons
|
||
|
||
|
||
```pycon
|
||
>>> 10 < 1
|
||
False
|
||
>>> 10 == 10
|
||
True
|
||
>>> 10 >= 20
|
||
False
|
||
```
|
||
|
||
notes:
|
||
|
||
Déconseiller l'utilisation de `is`, de toute facons PyLint leur dira
|
||
quand l'utiliser.
|
||
|
||
|
||
## Logique
|
||
|
||
```pycon
|
||
>>> True or False
|
||
True
|
||
>>> True and False
|
||
False
|
||
>>> not True
|
||
False
|
||
```
|
||
|
||
notes:
|
||
|
||
On utilisera ça plus tard, avec les structures de contrôle.
|
||
|
||
|
||
## Test d'appartenance
|
||
|
||
```pycon
|
||
>>> "chocolat" in "pain au chocolat"
|
||
True
|
||
```
|
||
|
||
|
||
## Test d'appartenance
|
||
|
||
```pycon
|
||
>>> "sel" in {"farine", "œuf", "sucre", "sel", "levure"}
|
||
True
|
||
```
|
||
|
||
|
||
## Travailler avec les ensembles
|
||
|
||
```pycon
|
||
>>> {"farine", "sel"} | {"œuf", "sel"} == {"sel", "farine", "œuf"}
|
||
True
|
||
```
|
||
|
||
notes:
|
||
|
||
C'est une union.
|
||
|
||
|
||
## Travailler avec les ensembles
|
||
|
||
```pycon
|
||
>>> {"farine", "levure", "sel"} & {"œuf", "sel", "sucre"}
|
||
{'sel'}
|
||
```
|
||
|
||
notes:
|
||
|
||
Une intersection.
|
||
|
||
|
||
## Mais en cas d'ambiguité…
|
||
|
||
```pycon
|
||
>>> "farine" * "sucre"
|
||
Traceback (most recent call last):
|
||
File "<stdin>", line 1, in <module>
|
||
TypeError: can't multiply sequence by non-int of type 'str'
|
||
```
|
||
|
||
|
||
## Mais en cas d'ambiguité…
|
||
|
||
```pycon
|
||
>>> {"farine", "levure"} + {"sel", "œuf"}
|
||
Traceback (most recent call last):
|
||
File "<stdin>", line 1, in <module>
|
||
TypeError: unsupported operand type(s) for +: 'set' and 'set'
|
||
```
|
||
|
||
|
||
# Les variables
|
||
|
||
## Affectation
|
||
|
||
```pycon
|
||
>>> preparation = 20
|
||
>>> cuisson = 30
|
||
>>> preparation + cuisson
|
||
50
|
||
```
|
||
|
||
notes:
|
||
|
||
JAMAIS dire : On met 20 dans « preparation ».
|
||
|
||
|
||
## Affectation multiple
|
||
|
||
```pycon
|
||
>>> preparation, cuisson = 20, 30
|
||
>>> preparation
|
||
20
|
||
>>> cuisson
|
||
30
|
||
```
|
||
|
||
|
||
## Accès par indice
|
||
|
||
```pycon
|
||
>>> etapes = ["preparation", "cuisson", "dégustation"]
|
||
>>> etapes[0]
|
||
'preparation'
|
||
>>> etapes[1]
|
||
'cuisson'
|
||
>>> etapes[2]
|
||
'dégustation'
|
||
```
|
||
|
||
notes:
|
||
|
||
On réutilise le nom pour accéder au contenu.
|
||
|
||
Bien prendre le temps d'expliquer la syntaxe ici.
|
||
|
||
|
||
## Accès par clé
|
||
|
||
```pycon
|
||
>>> definitions = {
|
||
... "un verre": "25 cl",
|
||
... "un petit verre": "12 cl",
|
||
... "qs": "quantité suffisante"
|
||
... }
|
||
...
|
||
>>> definitions["un petit verre"]
|
||
'12 cl'
|
||
```
|
||
|
||
|
||
# Les fonctions
|
||
|
||
## print
|
||
|
||
```pycon
|
||
>>> print("Brioche")
|
||
Brioche
|
||
```
|
||
|
||
notes:
|
||
|
||
C'est leur première fonction, s'attarder sur la syntaxe !
|
||
|
||
|
||
## print
|
||
|
||
```pycon
|
||
>>> print("La moitié de 130 g :", 130 // 2, "g")
|
||
La moitié de 130 g : 65 g
|
||
```
|
||
|
||
notes:
|
||
|
||
En effet, le P de REPL étant `print`, le print est implicite dans un REPL.
|
||
|
||
Mais le REPL sert a tester : on peut bien tester print dans le REPL.
|
||
|
||
Exercices:
|
||
- Print 42
|
||
- Number of seconds in a year
|
||
- Using operators
|
||
|
||
|
||
## str, list, int, ...
|
||
|
||
```pycon
|
||
>>> str(130)
|
||
'130'
|
||
```
|
||
|
||
## str, list, int, ...
|
||
|
||
```pycon
|
||
>>> int("130")
|
||
130
|
||
```
|
||
|
||
|
||
## len
|
||
|
||
```pycon
|
||
>>> len(["farine", "œufs", "sucre"])
|
||
3
|
||
>>> len("farine")
|
||
6
|
||
```
|
||
|
||
notes:
|
||
|
||
Exercise: Character counting
|
||
|
||
|
||
## range
|
||
|
||
```pycon
|
||
>>> list(range(10))
|
||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||
>>> list(range(5, 10))
|
||
[5, 6, 7, 8, 9]
|
||
```
|
||
|
||
|
||
## help
|
||
|
||
Affiche la documentation de n'importe quoi, essayez :
|
||
|
||
- `help(str)`
|
||
- `help(list)`
|
||
- ...
|
||
|
||
notes:
|
||
|
||
Accepte aussi une valeur (et donc une variable) mais attention : si la
|
||
variable est une chaîne, `help` n'affichera pas la documentation des
|
||
chaînes.
|
||
|
||
|
||
## sorted
|
||
|
||
```pycon
|
||
>>> sorted({"sel", "farine", "sucre"})
|
||
['farine', 'sel', 'sucre']
|
||
```
|
||
|
||
## Les importer des modules
|
||
|
||
```pycon
|
||
>>> from random import choice
|
||
>>> print(choice(["Pain au chocolat", "Chocolatine"]))
|
||
Pain au chocolat
|
||
```
|
||
|
||
notes:
|
||
|
||
Exercice : Import.
|
||
|
||
|
||
# Les instructions
|
||
|
||
## if
|
||
|
||
```pycon
|
||
>>> if "sucre" in ingredients and "œuf" in ingredients:
|
||
... print("Commencer par blanchir les œufs.")
|
||
Commencer par blanchir les œufs.
|
||
```
|
||
|
||
notes:
|
||
|
||
Parler de l'indentation !
|
||
|
||
Notez le `...`, on a du appyer un coup en « entrée » pour fermer ce bloc.
|
||
|
||
1 était premier, avant, mais ça casse le théorème « Every possible
|
||
whole number can be written as a _unique_ product of primes ».
|
||
|
||
|
||
## Le `else`
|
||
|
||
Après un bloc `if`, on peut ajouter un bloc `else` :
|
||
|
||
```pycon
|
||
>>> if "sucre" in ingredients and "œuf" in ingredients:
|
||
... print("Commencer par blanchir les œufs.")
|
||
... else:
|
||
... print("Commencer comme vous voulez.")
|
||
Commencer par blanchir les œufs.
|
||
```
|
||
|
||
|
||
## Le `elif`
|
||
|
||
Après un `if`, on peut ajouter un ou des bloc `elif` :
|
||
|
||
```pycon
|
||
>>> grams = 1250
|
||
>>> if grams == 0:
|
||
... print("Ne pas en mettre")
|
||
... elif grams < 1000:
|
||
... print("En mettre", grams, "grammes.")
|
||
... else:
|
||
... kg, g = divmod(grams, 1000)
|
||
... print("En mettre", kg, "kg", "et", g, "g.")
|
||
...
|
||
En mettre 1 kg et 250 g.
|
||
```
|
||
|
||
notes:
|
||
|
||
Parler de `pass` et de `...`.
|
||
|
||
|
||
## for
|
||
|
||
```pycon
|
||
>>> for ingredient in ingredients:
|
||
... print(ingredient)
|
||
...
|
||
sel
|
||
farine
|
||
sucre
|
||
levure
|
||
beurre
|
||
œuf
|
||
```
|
||
|
||
```pycon
|
||
>>> ingredient = ingredients[0]
|
||
>>> print(ingredient)
|
||
sel
|
||
>>> ingredient = ingredients[1]
|
||
>>> print(ingredient)
|
||
farine
|
||
>>> ingredient = ingredients[2]
|
||
>>> print(ingredient)
|
||
sucre
|
||
```
|
||
|
||
|
||
## for
|
||
|
||
```pycon
|
||
>>> for lettre in "Œuf":
|
||
... print(lettre)
|
||
...
|
||
Œ
|
||
u
|
||
f
|
||
>>>
|
||
```
|
||
|
||
|
||
## for
|
||
|
||
```pycon
|
||
>>> for i in range(5):
|
||
... print(i)
|
||
0
|
||
1
|
||
2
|
||
3
|
||
4
|
||
```
|
||
|
||
notes:
|
||
|
||
Exercice : Square numbers, powers of two, comparisons.
|
||
|
||
|
||
## L'instruction `while`
|
||
|
||
Très rarement utilisée car le `for` est bien plus pratique, sert
|
||
cependant dans quelques cas:
|
||
|
||
- `while True:`
|
||
- `while il_reste_du_travail_à_faire:`
|
||
|
||
|
||
## L'instruction `while`
|
||
|
||
```pycon
|
||
>>> while il_reste_de_la_pâte:
|
||
... faire_une_crêpe()
|
||
...
|
||
```
|
||
|
||
|
||
# Les méthodes
|
||
|
||
## Sur les chaînes
|
||
|
||
```pycon
|
||
>>> s = "Pâte à crêpe"
|
||
>>> s.count("e")
|
||
2
|
||
>>> s.startswith("Pâte")
|
||
True
|
||
>>> s.split()
|
||
['Pâte', 'à', 'crêpe']
|
||
```
|
||
|
||
notes:
|
||
|
||
Exercise : Counting Words.
|
||
|
||
|
||
## Sur les chaînes
|
||
|
||
```pycon
|
||
>>> s = "Durée : {} minutes."
|
||
>>> s.format(3600 // 60)
|
||
'Durée : 60 minutes.'
|
||
```
|
||
|
||
|
||
## Sur les listes
|
||
|
||
```pycon
|
||
>>> ingredients = ["1 kg de farine", "12 œufs"]
|
||
>>> ingredients.append("130 g de beurre")
|
||
>>> ingredients
|
||
['1 kg de farine', '12 œufs', '130 g de beurre']
|
||
```
|
||
|
||
|
||
## Sur les dictionnaires
|
||
|
||
```pycon
|
||
>>> definitions = {
|
||
... "un verre": "25 cl",
|
||
... "un petit verre": "12 cl",
|
||
... "qs": "quantité suffisante"
|
||
... }
|
||
>>> definitions.items()
|
||
dict_items([('un verre', '25 cl'), ('un petit verre', '12 cl'), ('qs', 'quantité suffisante')])
|
||
```
|
||
|
||
|
||
# Les variables (suite)
|
||
|
||
## Le type des variables
|
||
|
||
En Python, les variables ne sont que des noms.
|
||
|
||
Des « étiquettes » qu'on colle aux objets.
|
||
|
||
> Comme sur les pots de confiture.
|
||
|
||
|
||
## Le type des variables
|
||
|
||
Seules les valeurs sont typées.
|
||
|
||
> L'étiquette n'a pas de goût, c'est la confiture qui a du goût.
|
||
|
||
notes:
|
||
|
||
Toutes les valeurs sont des objets.
|
||
|
||
Sans. Exceptions.
|
||
|
||
On peut « coller » plusieurs étiquettes à une même valeur.
|
||
|
||
C'est pour ça que pour `n = 10` on dit "n est assigné à 10", et non "10 est mis dans n".
|
||
|
||
|
||
## Immuables vs modifiables
|
||
|
||
Certains types sont modifiables, d'autres, non.
|
||
|
||
notes:
|
||
|
||
On dit qu'elles sont immuables (*immutable* en anglais).
|
||
|
||
Attention, les variables sont toujours ... variables, nous n'avons pas
|
||
de constantes.
|
||
|
||
|
||
## Les types modifiables
|
||
|
||
- On peut ajouter à une liste.
|
||
- On peut vider un ensemble.
|
||
- On peut supprimer une clef d'un dictionnaire.
|
||
- ...
|
||
|
||
notes:
|
||
|
||
- Listes
|
||
- Dictionnaires
|
||
- Ensembles
|
||
- ...
|
||
|
||
|
||
## Les types immuables
|
||
|
||
- On ne peut pas dire que maintenant 10 vaut 12.
|
||
- Ni que faux devient vrai.
|
||
- Ni qu'une paire contient maintenant trois éléments.
|
||
- ...
|
||
|
||
notes:
|
||
|
||
- Les chaînes
|
||
- Les *n*-uplets
|
||
- Les entiers
|
||
- Les booléens
|
||
- ...
|
||
|
||
Pour les chaînes c'est discutable, mais avoir des chaînes immuables
|
||
est confortable (clef de dictionnaires par exemple, ou la garantie
|
||
qu'un appel à une fonction avec une chaîne en paramètre ne va pas la
|
||
modifier).
|
||
|
||
|
||
## La vérité
|
||
|
||
En Python, ce qui est vide est faux, `0` est faux, `None` est faux,
|
||
`False` est faux. Le reste est vrai :
|
||
|
||
```pycon
|
||
>>> bool("Non vide")
|
||
True
|
||
>>> bool([]) # Une liste vide
|
||
False
|
||
>>> bool(0.0)
|
||
False
|
||
```
|
||
|
||
notes:
|
||
|
||
Attention à la sémantique : `if foo` est différent de `if foo is True`.
|
||
|
||
Leur rappeler que c'est pylint qui leur dira quand utiliser `is`, leur
|
||
dire quand même : pour `True`, `False`, et `None`.
|
||
|
||
|
||
# Les fonctions
|
||
|
||
## Syntaxe
|
||
|
||
```python
|
||
def ma_fonction(ses_paramètres):
|
||
... # Le code de la fonction
|
||
```
|
||
|
||
notes:
|
||
|
||
Passer du temps sur la syntaxe et le vocabulaire
|
||
- fonction
|
||
- paramètre, argument
|
||
- `return`
|
||
|
||
|
||
## Exemple
|
||
|
||
```pycon
|
||
>>> def temps_total(temps_de_preparation, temps_de_cuisson):
|
||
... return temps_de_preparation + temps_de_cuisson
|
||
...
|
||
>>> temps_total(30, 20)
|
||
50
|
||
```
|
||
|
||
## Paramètres
|
||
|
||
Une fonction prend des paramètres et renvoie une valeur.
|
||
|
||
```python
|
||
def fahrenheit_to_celsius(fahrenheit):
|
||
return (fahrenheit - 32) * 5/9
|
||
```
|
||
|
||
## Arguments
|
||
|
||
On peut donc lui donner des arguments :
|
||
```pycon
|
||
>>> fahrenheit_to_celsius(320)
|
||
160.0
|
||
>>> fahrenheit_to_celsius(390)
|
||
198.88888888888889
|
||
>>> fahrenheit_to_celsius(450)
|
||
232.22222222222223
|
||
```
|
||
|
||
notes:
|
||
|
||
Exercices: First function, Print even numbers, ...
|
||
|
||
|
||
# Les chaînes
|
||
|
||
```pycon
|
||
>>> """Elle préfère "l'huile d'olive"."""
|
||
'Elle préfère "l\'huile d\'olive".'
|
||
```
|
||
|
||
notes:
|
||
|
||
~ fin de jour 1 début de jour 2
|
||
|
||
|
||
## Les docstrings
|
||
|
||
```python
|
||
def une_fonction():
|
||
"""Une courte description."""
|
||
...
|
||
return ...
|
||
```
|
||
|
||
# Les nombres
|
||
|
||
## Les opérateurs mathématiques
|
||
|
||
```pycon
|
||
>>> 0.1 + 0.1
|
||
0.2
|
||
```
|
||
|
||
|
||
## Les opérateurs mathématiques
|
||
|
||
```pycon
|
||
>>> 0.1 + 0.2
|
||
0.30000000000000004
|
||
```
|
||
|
||
notes:
|
||
|
||
https://0.30000000000000004.com
|
||
|
||
|
||
# `for` et `while`
|
||
|
||
## `break` et `continue`
|
||
|
||
`break` sert à interrompre une boucle, `continue` sert à passer à
|
||
l'élément suivant. Qu'on soit dans un `for` ou dans un `while`.
|
||
|
||
|
||
## `break`
|
||
|
||
```pycon
|
||
>>> while True:
|
||
... if not il_reste_de_la_pâte:
|
||
... break
|
||
... faire_une_crêpe()
|
||
...
|
||
```
|
||
|
||
|
||
## `continue`
|
||
|
||
```pycon-repl
|
||
>>> for recette in recettes:
|
||
... if "sésame" in recette["ingredients"]:
|
||
... continue
|
||
... if "noix de Pécan" in recette["ingredients"]:
|
||
... continue
|
||
... print(recette["titre"])
|
||
Broyés du Poitou
|
||
Œufs mimosa
|
||
Houmous
|
||
```
|
||
|
||
|
||
## Les exceptions : `try`
|
||
|
||
```pycon
|
||
>>> try:
|
||
... int("2 kg")
|
||
... except ValueError:
|
||
... print("Raté")
|
||
Raté
|
||
```
|
||
|
||
|
||
# La notation en compréhension
|
||
|
||
C'est transformer ça :
|
||
|
||
```pycon
|
||
>>> durées = []
|
||
>>> for recette in recettes:
|
||
... durées.append(recette["durée"])
|
||
>>> durées
|
||
[35, 20, 13]
|
||
```
|
||
|
||
|
||
## La notation en compréhension
|
||
|
||
en :
|
||
|
||
```pycon
|
||
>>> [recette["durée"] for recette in recettes]
|
||
[35, 20, 13]
|
||
```
|
||
|
||
|
||
## La notation en compréhension
|
||
|
||
Ou :
|
||
|
||
```python
|
||
def compte_recettes(recettes, ingrédient):
|
||
trouvées = []
|
||
for recette in recettes:
|
||
if ingrédient in recette["ingredients"]:
|
||
trouvées.append(recette)
|
||
return len(trouvées)
|
||
```
|
||
|
||
|
||
## La notation en compréhension
|
||
|
||
en :
|
||
|
||
```python
|
||
def compte_recettes(recettes, ingrédient):
|
||
return len(
|
||
[
|
||
recette
|
||
for recette in recettes
|
||
if ingrédient in recette["ingredients"]
|
||
]
|
||
)
|
||
```
|
||
|
||
notes:
|
||
|
||
Elle devrait s'écrire sur une seule ligne, mais, vidéoprojecteur...
|
||
|
||
|
||
|
||
# Les *slices*
|
||
|
||
*slices* en anglais
|
||
|
||
notes:
|
||
|
||
On pourrait traduire par « tranches » et filer la métaphore culinaire…
|
||
|
||
['incontestable', 'contestable', 'testable', 'stable']
|
||
|
||
```python
|
||
seq = 'incontestable'
|
||
```
|
||
|
||
## Les *slices*
|
||
|
||
```pycon
|
||
>>> seq = 'incontestable'
|
||
>>> seq[0]
|
||
'i'
|
||
```
|
||
|
||
|
||
## Les *slices*
|
||
|
||
```text
|
||
11
|
||
0123456789 |
|
||
incontestable—12
|
||
|
|
||
10
|
||
|
||
```
|
||
```pycon
|
||
>>> seq[5:9]
|
||
'test'
|
||
>>> seq[5:13]
|
||
'testable'
|
||
>>> seq[7:13]
|
||
'stable'
|
||
```
|
||
|
||
## Les *slices*
|
||
|
||
```pycon
|
||
>>> seq[:2]
|
||
'in'
|
||
>>> seq[2:]
|
||
'contestable'
|
||
```
|
||
|
||
|
||
## Les *slices*
|
||
|
||
```pycon
|
||
>>> seq[-1]
|
||
'e'
|
||
```
|
||
|
||
|
||
## Les *slices*
|
||
|
||
```pycon
|
||
>>> seq[-6:]
|
||
'stable'
|
||
```
|
||
|
||
|
||
## Les *slices*
|
||
|
||
```pycon
|
||
>>> "perso"[::2]
|
||
'pro'
|
||
```
|
||
|
||
|
||
notes:
|
||
|
||
```python
|
||
dict = ['ados', 'assit', 'engager', 'éroder', 'épater', 'ivres', 'soda', 'tissa', 'regagne', 'erodé', 'retapé', 'servi']
|
||
```
|
||
|
||
## Les *slices*
|
||
|
||
```pycon
|
||
>>> for word in dict:
|
||
... if word[::-1] in dict:
|
||
... print(word, word[::-1])
|
||
ados soda
|
||
assit tissa
|
||
engager regagne
|
||
épater retapé
|
||
ivres servi
|
||
soda ados
|
||
tissa assit
|
||
regagne engager
|
||
retapé épater
|
||
servi ivres
|
||
```
|
||
|
||
|
||
## Les *slices*
|
||
|
||
`seq[<start>:<stop>:<step>]`
|
||
|
||
|
||
# Les classes
|
||
|
||
## La syntaxe
|
||
|
||
```python
|
||
class LeNomDeLaClasse:
|
||
"""Sa docstring, comme pour une
|
||
fonction.
|
||
"""
|
||
# Le corps de la classe.
|
||
```
|
||
|
||
Notes:
|
||
|
||
Dédiaboliser l'héritage, l'héritage multiple, les interfaces,
|
||
les classes abstraites, les méthodes virtuelles, ...
|
||
|
||
|
||
## À retenir
|
||
|
||
On pourrait trier les données en deux types :
|
||
|
||
- celles dont on connaît les attributs → classes
|
||
- celles dont on ne connaît pas les attributs → dictionnaires
|
||
|
||
|
||
Notes:
|
||
|
||
Le contexte, le métier, les bibliothèques utilisées peuvent générer
|
||
des cas particuliers, cette règle n'est pas absolue.
|
||
|
||
préciser peut être : "dont on connaît à toutes les étapes du programme".
|
||
|
||
|
||
|
||
## Exemple
|
||
|
||
```python
|
||
class Point:
|
||
def __init__(self, x, y):
|
||
self.x = x
|
||
self.y = y
|
||
```
|
||
|
||
Notes: On connaît les attributs.
|
||
|
||
|
||
## Exemple
|
||
|
||
```pycon
|
||
>>> ISIN = {
|
||
... "GLE": "FR0000130809",
|
||
... "PARRO": "FR0004038263",
|
||
... "AM": "FR0000121725",
|
||
... }
|
||
```
|
||
|
||
Notes: On ne les connaît pas.
|
||
|
||
|
||
## Syntaxe → les méthodes
|
||
|
||
```python
|
||
class Dice:
|
||
def throw(self):
|
||
self.value = randint(1, 6)
|
||
```
|
||
|
||
Notes: Une classe *ne sert pas* à stocker des fonctions, mais des
|
||
données. Pensez aux structs C.
|
||
|
||
La données d'abord, l'algorithme après.
|
||
|
||
|
||
## Syntaxe → le constructeur
|
||
|
||
```python
|
||
class DiceCup:
|
||
def __init__(self, dices):
|
||
self.dices = dices
|
||
|
||
def shake(self):
|
||
...
|
||
```
|
||
|
||
Notes: Leur faire faire implémenter le __repr__, min, max, et mean.
|
||
|
||
Leur faire faire 1000 tirages dans un Counter, avec des valeurs ENTIẼRES.
|
||
|
||
BiaisedDice(Dice) est un bon exemple d'héritage.
|
||
|
||
|
||
## Utilisation
|
||
|
||
```pycon
|
||
>>> dice = Dice()
|
||
>>> dice.throw()
|
||
>>> dice.value
|
||
4
|
||
```
|
||
|
||
|
||
## Utilisation
|
||
|
||
```pycon
|
||
>>> cup = DiceCup(
|
||
... [Dice() for _ in range(10)]
|
||
... )
|
||
>>> cup.shake()
|
||
```
|
||
|
||
Notes:
|
||
|
||
Faire quelques exemples d'héritage simples avant de passer a la suite.
|
||
|
||
super() considered super() !
|
||
|
||
|
||
# pip, venvs, conda
|
||
|
||
|
||
## pip
|
||
|
||
C'est l'outil standard pour installer un paquet.
|
||
|
||
```bash
|
||
$ python3 -m pip install <package-name>
|
||
```
|
||
|
||
Mais, ça installe où ?
|
||
|
||
|
||
## venv
|
||
|
||
C'est l'outil standard pour indiquer où installer les paquets.
|
||
|
||
*On peut ainsi avoir plusieurs environnements, un par projet par exemple*.
|
||
|
||
Notes:
|
||
|
||
Pratique pour avoir des versions différentes.
|
||
|
||
|
||
## venv
|
||
|
||
```bash
|
||
$ python3 -m venv --prompt test .venv/
|
||
$ source .venv/bin/activate
|
||
(test) $ python3 -m pip install pytest
|
||
```
|
||
|
||
Notes: Dépendant du shell, les envoyer sur library/venv.html.
|
||
Insister sur le côté "trashable du venv" :
|
||
- Ne rien mettre dans .venv
|
||
- rm -fr .venv # au moindre souci
|
||
|
||
|
||
## conda
|
||
|
||
```bash
|
||
$ conda create --name test
|
||
$ conda activate test
|
||
(test) $ conda install numpy
|
||
```
|
||
|
||
|
||
# Tester
|
||
|
||
## pytest
|
||
|
||
```bash
|
||
(test) $ mkdir tests/
|
||
(test) $ pip install pytest
|
||
(test) $ editor tests/test_dice.py
|
||
```
|
||
|
||
Notes: C'est l'occasion de parler de assert.
|
||
|
||
|
||
## hypothesis
|
||
|
||
```python
|
||
from hypothesis import given
|
||
from hypothesis.strategies import integers
|
||
|
||
@given(integers(min_value=2,
|
||
max_value=1000))
|
||
def test_fib(i):
|
||
assert fib(i) == fib(i-1) + fib(i-2)
|
||
```
|
||
|
||
|
||
# Les bonnes pratiques
|
||
|
||
Notes: Prérequis: pip et venv.
|
||
|
||
~fin jour 2 / début jour 3.
|
||
|
||
## Bonnes habitudes
|
||
|
||
> There are 2 hard problems in computer science: cache invalidation,
|
||
> naming things, and off-by-1 errors.
|
||
|
||
|
||
## Bonnes habitudes
|
||
|
||
Pas plus de 7.
|
||
|
||
|
||
## Garder son code lisible
|
||
|
||
Attention au code vieillissant, au « je ne rajoute qu'une ligne ou
|
||
deux à cette fonction et c'est réglé ».
|
||
|
||
Notes: Deux ans après la fonction fait 800 lignes, et personne ne l'a
|
||
vu venir. flake8 peut aider.
|
||
|
||
|
||
## Les « linters »
|
||
|
||
Il existe plusieurs outils pour « relire » votre code :
|
||
- flake8,
|
||
- pylint,
|
||
- mypy,
|
||
- black,
|
||
- bandit,
|
||
- isort.
|
||
|
||
Et un pour les unifier tous : `tox`.
|
||
|
||
Notes: Leur faire implémenter un `is_prime(x)` pour jouer avec.
|
||
|
||
La règle des 7.
|
||
|
||
|
||
## flake8
|
||
|
||
Dans un venv :
|
||
|
||
```bash
|
||
(test) $ pip install flake8
|
||
(test) $ pip install flake8-bugbear
|
||
(test) $ flake8 --max-complexity 9 *.py
|
||
```
|
||
|
||
Notes:
|
||
|
||
Flake8 est rapide, n'effectuant pas les `imports` il ne peut repérer
|
||
qu'une catégorie de problèmes.
|
||
|
||
9 est trop bas, 15 est probablement un bon choix.
|
||
|
||
|
||
## pylint
|
||
|
||
```bash
|
||
(test) $ pip install pylint
|
||
(test) $ pylint is_prime.py
|
||
```
|
||
|
||
|
||
## mypy
|
||
|
||
`mypy` fonctionne avec des annotations de types.
|
||
|
||
```bash
|
||
(test) $ pip install mypy
|
||
(test) $ mypy is_prime.py
|
||
```
|
||
|
||
Notes: --ignore-missing-imports
|
||
|
||
|
||
## bandit
|
||
|
||
Bandit cherche les failles de sécurité...
|
||
|
||
```bash
|
||
(test) $ pip install bandit
|
||
(test) $ bandit is_prime.py
|
||
```
|
||
|
||
|
||
## tox
|
||
|
||
Permet de lancer les tests:
|
||
- sur plusieurs interpréteurs (s'ils sont installés),
|
||
- de plusieurs outils,
|
||
- en parallèle.
|
||
|
||
Notes: c.f. gh/JulienPalard/oeis.
|
||
|
||
|
||
## pdb
|
||
|
||
```
|
||
breakpoint()
|
||
```
|
||
|
||
|
||
## PYTHONDEVMODE=y
|
||
|
||
Et `./configure --with-pydebug`.
|
||
|
||
Notes: Voir mon bashrc :] Surtout "viable" depuis la 3.8.
|
||
|
||
|
||
|
||
# `*`, `**`
|
||
|
||
|
||
## `*`
|
||
|
||
Signifie « plusieurs », comme dans une liste ou un *n*-uplet.
|
||
|
||
```pycon
|
||
>>> begin, *rest = range(5)
|
||
>>> begin
|
||
0
|
||
>>> rest
|
||
[1, 2, 3, 4]
|
||
```
|
||
|
||
Notes:
|
||
|
||
Attention, initiation : Le but est de savoir que ça existe, savoire le
|
||
lire.
|
||
|
||
Équivaut à:
|
||
begin, rest = seq[0], seq[1:]
|
||
|
||
|
||
|
||
|
||
## `*`
|
||
|
||
```pycon
|
||
>>> def sum(*args):
|
||
... print(args)
|
||
...
|
||
>>> sum(1, 2, 3, 4, 5)
|
||
(1, 2, 3, 4, 5)
|
||
```
|
||
|
||
|
||
## `*`
|
||
|
||
```pycon
|
||
>>> [0, 0, 0, *range(3)]
|
||
[0, 0, 0, 0, 1, 2]
|
||
```
|
||
|
||
|
||
## `*`
|
||
|
||
```pycon
|
||
>>> print(*range(5))
|
||
0 1 2 3 4
|
||
```
|
||
|
||
|
||
## `**`
|
||
|
||
Signifie « plusieurs, nommés », comme dans un dictionnaire.
|
||
|
||
|
||
```pycon
|
||
>>> def p(**kwargs):
|
||
... for key, value in kwargs.items():
|
||
... print(key, "→", value)
|
||
...
|
||
>>> p(x=10, y=12)
|
||
x → 10
|
||
y → 12
|
||
```
|
||
|
||
|
||
## `**`
|
||
|
||
```pycon
|
||
>>> defaults = {"path": "./",
|
||
... "pattern": "*.txt"}
|
||
>>> {**defaults, "pattern": "*.md"}
|
||
{'path': './', 'pattern': '*.md'}
|
||
```
|
||
|
||
|
||
## `**`
|
||
|
||
```pycon
|
||
>>> def p(x, y):
|
||
... print(f"x → {x}")
|
||
... print(f"y → {y}")
|
||
...
|
||
>>> point = {"x": 10, "y": 12}
|
||
>>> p(**point)
|
||
x → 10
|
||
y → 12
|
||
```
|
||
|
||
|
||
# L'encodage
|
||
|
||
|
||
## encoder
|
||
|
||
C'est transformer une chaîne en octets, pour son transport ou stockage :
|
||
|
||
```pycon
|
||
>>> "L'été".encode()
|
||
b"L'\xc3\xa9t\xc3\xa9"
|
||
>>> list("L'été".encode())
|
||
[76, 39, 195, 169, 116, 195, 169]
|
||
```
|
||
|
||
|
||
## décoder
|
||
|
||
C'est le contraire ...
|
||
|
||
```pycon
|
||
>>> bytes([76, 39, 195, 169, 116, 195, 169]).decode()
|
||
"L'été"
|
||
```
|
||
|
||
Notes:
|
||
|
||
Parler d'unicode, d'UTF-8, de latin-1. Ne pas oubilier de mentionner
|
||
que latin-1 et companie sont à taille fixe, et qu'UTF-8 est à taille
|
||
variable.
|
||
|
||
|
||
# Les modules utiles
|
||
|
||
- argparse
|
||
- re
|
||
- csv (quand on a pas Pandas)
|
||
- subprocess
|
||
|
||
|
||
# La communauté
|
||
|
||
> Come for the language, stay for the community
|
||
|
||
— Brett Cannon
|
||
|
||
|
||
|
||
## Les PyCons
|
||
|
||
La PyConFr (tous les ans, sauf cette année) ! Les meetups locaux hors période de pandémie !
|