# 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 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 "", line 1, in 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 "", line 1, in 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 "", line 1, in 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[::]` # 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 ``` 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 !