diff --git a/background.jpg b/background.jpg new file mode 100644 index 0000000..714dbd0 Binary files /dev/null and b/background.jpg differ diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..a697f48 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +if ! which cutycapt >/dev/null +then + echo Please apt install cutycapt + exit 1 +fi + +if ! which pytest >/dev/null +then + echo Please pip install -r requirements.txt + exit 1 +fi + +set -e # So a breaking test stops the deploy. + +export QT_QPA_PLATFORM=offscreen + +for makefile in */Makefile +do + dir="$(dirname "$makefile")" + figlet -C utf8 -t "$dir" + ( + cd "$dir" + + make test + make rsync + ) +done diff --git a/python-avancé/python-avancé.md b/python-avancé/python-avancé.md index d312bbb..361cc0d 100644 --- a/python-avancé/python-avancé.md +++ b/python-avancé/python-avancé.md @@ -359,26 +359,6 @@ En initiation on dit "ça ne vous servira pas". En avancé on dit Notes: -```python -class M(type): - def __new__(cls, *args, **kwargs): - print(f"meta.__new__(*{args}, **{kwargs})") - return super().__new__(cls, *args, **kwargs) - - def __init__(self, *args, **kwargs): - print(f"meta.__init__(*{args}, **{kwargs})") - super().__init__(*args, **kwargs) - -class MyCls(metaclass=M): - def __new__(cls, *args, **kwargs): - print(f"cls.__new__(*{args}, **{kwargs})") - return super().__new__(cls, *args, **kwargs) - - def __init__(self, *args, **kwargs): - print(f"cls.__init__(*{args}, **{kwargs})") - super().__init__(*args, **kwargs) -``` - Vous pouvez aussi utiliser un décorateur pour personaliser une classe. @@ -906,7 +886,7 @@ Dans l'attribut `value`. ## await -``` +```text async def two(): return 2 @@ -963,8 +943,11 @@ def coro_manager(coro): coro.send(None) except StopIteration as stop: return stop.value +``` -print(coro_manager(four())) +```pycon +>>> print(coro_manager(four())) +4 ``` @@ -981,7 +964,7 @@ async def wont_terminate_here(): print("Terminated") return 42 -print(coro_manager(wont_terminate_here())) +coro_manager(wont_terminate_here()) ``` ## Gérer ses coroutines @@ -1016,14 +999,14 @@ def frenetic_coros_manager(*coros): ## Gérer ses coroutines -```python +```text async def tum(): - for _ in range(10): # ou : while True: + while True: await Awaitable() print("Tum") async def pak(): - for _ in range(10): # ou : while True: + while True: await Awaitable() print("Pak") diff --git a/python-initiation/initiation.md b/python-initiation/initiation.md index 201b0b8..235a021 100644 --- a/python-initiation/initiation.md +++ b/python-initiation/initiation.md @@ -135,7 +135,7 @@ In [1]: ## Testons l'interpréteur -```python +```pycon >>> 10 10 ``` @@ -150,7 +150,7 @@ pour qu'on puisse le lire. ## C'est votre nouvelle calculatrice -```python +```pycon >>> 60 * 60 * 4 14400 ``` @@ -158,7 +158,7 @@ pour qu'on puisse le lire. ## Les exceptions -```python +```pycon >>> 5 / 0 Traceback (most recent call last): File "", line 1, in @@ -174,7 +174,7 @@ Lisez *TOUJOURS* la dernière ligne en premier ! ## Booléens -```python +```pycon >>> True True >>> False @@ -185,7 +185,7 @@ False ## Nombres -```python +```pycon >>> 42 42 ``` @@ -193,7 +193,7 @@ False ## Nombres -```python +```pycon >>> 18446744073709551616 18446744073709551616 ``` @@ -201,7 +201,7 @@ False ## Nombres -```python +```pycon >>> 3.1415 3.1415 ``` @@ -209,7 +209,7 @@ False ## Chaînes de caractères -```python +```pycon >>> "Beurre ou huile d'olive ?" "Beurre ou huile d'olive ?" ``` @@ -222,7 +222,7 @@ dans un cours de C89. ## Chaînes de caractères -```python +```pycon >>> 'Cuisson "au beurre" !!' 'Cuisson "au beurre" !!' ``` @@ -234,7 +234,7 @@ Les triples quotes apparaissent jour 2. ## Listes -```python +```pycon >>> ["1 kg de farine", "12 œufs", "130 g de beurre"] ['1 kg de farine', '12 œufs', '130 g de beurre'] ``` @@ -246,7 +246,7 @@ La représentation est souvent du Python valide. ## Listes -```python +```pycon >>> ["farine", 1000] ['farine', 1000] ``` @@ -258,7 +258,7 @@ Attention à ne pas abuser du mélange autorisé des types. ## *n*-uplets, *tuple* -```python +```pycon >>> ("œufs", 12) ('œufs', 12) >>> ("sucre", 130) @@ -275,7 +275,7 @@ liste, par exemple des coordonnées : (x, y). ## Listes et tuples -```python +```pycon >>> [("farine", 1000), ("œufs", 12), ("sucre", 130)] [('farine', 1000), ('œufs', 12), ('sucre', 130)] ``` @@ -316,7 +316,7 @@ pas les clefs à l'avance, sinon c'est une classe. ## Les opérateurs mathématiques -```python +```pycon >>> 10 + 10 20 >>> 10.5 + 2 @@ -326,14 +326,14 @@ pas les clefs à l'avance, sinon c'est une classe. ## Les opérateurs mathématiques -```python +```pycon >>> (4 * 10**1) + (2 * 10**0) 42 ``` ## Les opérateurs mathématiques -```python +```pycon >>> 10 / 2 5.0 ``` @@ -341,7 +341,7 @@ pas les clefs à l'avance, sinon c'est une classe. ## Les opérateurs -```python +```pycon >>> "Bri" + "oche" 'Brioche' ``` @@ -353,7 +353,7 @@ It's called concatenation of strings. ## Les opérateurs -```python +```pycon >>> "mur" * 2 'murmur' ``` @@ -365,7 +365,7 @@ Tant qu'il n'y a pas d'ambiguité, c'est implémenté. ## Les opérateurs -```python +```pycon >>> ["farine", "œufs"] + ["sucre", "sel"] ['farine', 'œufs', 'sucre', 'sel'] ``` @@ -374,7 +374,7 @@ Tant qu'il n'y a pas d'ambiguité, c'est implémenté. ## Les Comparisons -```python +```pycon >>> 10 < 1 False >>> 10 == 10 @@ -391,7 +391,7 @@ quand l'utiliser. ## Logique -```python +```pycon >>> True or False True >>> True and False @@ -407,7 +407,7 @@ On utilisera ça plus tard, avec les structures de contrôle. ## Test d'appartenance -```python +```pycon >>> "chocolat" in "pain au chocolat" True ``` @@ -415,7 +415,7 @@ True ## Test d'appartenance -```python +```pycon >>> "sel" in {"farine", "œuf", "sucre", "sel", "levure"} True ``` @@ -423,7 +423,7 @@ True ## Travailler avec les ensembles -```python +```pycon >>> {"farine", "sel"} | {"œuf", "sel"} == {"sel", "farine", "œuf"} True ``` @@ -435,7 +435,7 @@ C'est une union. ## Travailler avec les ensembles -```python +```pycon >>> {"farine", "levure", "sel"} & {"œuf", "sel", "sucre"} {'sel'} ``` @@ -447,7 +447,7 @@ Une intersection. ## Mais en cas d'ambiguité… -```python +```pycon >>> "farine" * "sucre" Traceback (most recent call last): File "", line 1, in @@ -457,7 +457,7 @@ TypeError: can't multiply sequence by non-int of type 'str' ## Mais en cas d'ambiguité… -```python +```pycon >>> {"farine", "levure"} + {"sel", "œuf"} Traceback (most recent call last): File "", line 1, in @@ -469,7 +469,7 @@ TypeError: unsupported operand type(s) for +: 'set' and 'set' ## Affectation -```python +```pycon >>> preparation = 20 >>> cuisson = 30 >>> preparation + cuisson @@ -483,7 +483,7 @@ JAMAIS dire : On met 20 dans « preparation ». ## Affectation multiple -```python +```pycon >>> preparation, cuisson = 20, 30 >>> preparation 20 @@ -494,7 +494,7 @@ JAMAIS dire : On met 20 dans « preparation ». ## Accès par indice -```python +```pycon >>> etapes = ["preparation", "cuisson", "dégustation"] >>> etapes[0] 'preparation' @@ -513,7 +513,7 @@ Bien prendre le temps d'expliquer la syntaxe ici. ## Accès par clé -```python +```pycon >>> definitions = { ... "un verre": "25 cl", ... "un petit verre": "12 cl", @@ -529,7 +529,7 @@ Bien prendre le temps d'expliquer la syntaxe ici. ## print -```python +```pycon >>> print("Brioche") Brioche ``` @@ -541,7 +541,7 @@ C'est leur première fonction, s'attarder sur la syntaxe ! ## print -```python +```pycon >>> print("La moitié de 130 g :", 130 // 2, "g") La moitié de 130 g : 65 g ``` @@ -560,14 +560,14 @@ Exercices: ## str, list, int, ... -```python +```pycon >>> str(130) '130' ``` ## str, list, int, ... -```python +```pycon >>> int("130") 130 ``` @@ -575,7 +575,7 @@ Exercices: ## len -```python +```pycon >>> len(["farine", "œufs", "sucre"]) 3 >>> len("farine") @@ -589,7 +589,7 @@ Exercise: Character counting ## range -```python +```pycon >>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> list(range(5, 10)) @@ -614,14 +614,14 @@ chaînes. ## sorted -```python +```pycon >>> sorted({"sel", "farine", "sucre"}) ['farine', 'sel', 'sucre'] ``` ## Les importer des modules -```python +```pycon >>> from random import choice >>> print(choice(["Pain au chocolat", "Chocolatine"])) Pain au chocolat @@ -636,7 +636,7 @@ Exercice : Import. ## if -```python +```pycon >>> if "sucre" in ingredients and "œuf" in ingredients: ... print("Commencer par blanchir les œufs.") Commencer par blanchir les œufs. @@ -656,7 +656,7 @@ whole number can be written as a _unique_ product of primes ». Après un bloc `if`, on peut ajouter un bloc `else` : -```python +```pycon >>> if "sucre" in ingredients and "œuf" in ingredients: ... print("Commencer par blanchir les œufs.") ... else: @@ -669,7 +669,7 @@ Commencer par blanchir les œufs. Après un `if`, on peut ajouter un ou des bloc `elif` : -```python +```pycon >>> grams = 1250 >>> if grams == 0: ... print("Ne pas en mettre") @@ -689,7 +689,7 @@ Parler de `pass` et de `...`. ## for -```python +```pycon >>> for ingredient in ingredients: ... print(ingredient) ... @@ -701,7 +701,7 @@ beurre œuf ``` -```python +```pycon >>> ingredient = ingredients[0] >>> print(ingredient) sel @@ -716,7 +716,7 @@ sucre ## for -```python +```pycon >>> for lettre in "Œuf": ... print(lettre) ... @@ -729,7 +729,7 @@ f ## for -```python +```pycon >>> for i in range(5): ... print(i) 0 @@ -755,7 +755,7 @@ cependant dans quelques cas: ## L'instruction `while` -```python +```pycon >>> while il_reste_de_la_pâte: ... faire_une_crêpe() ... @@ -766,7 +766,7 @@ cependant dans quelques cas: ## Sur les chaînes -```python +```pycon >>> s = "Pâte à crêpe" >>> s.count("e") 2 @@ -783,7 +783,7 @@ Exercise : Counting Words. ## Sur les chaînes -```python +```pycon >>> s = "Durée : {} minutes." >>> s.format(3600 // 60) 'Durée : 60 minutes.' @@ -792,7 +792,7 @@ Exercise : Counting Words. ## Sur les listes -```python +```pycon >>> ingredients = ["1 kg de farine", "12 œufs"] >>> ingredients.append("130 g de beurre") >>> ingredients @@ -802,7 +802,7 @@ Exercise : Counting Words. ## Sur les dictionnaires -```python +```pycon >>> definitions = { ... "un verre": "25 cl", ... "un petit verre": "12 cl", @@ -894,7 +894,7 @@ modifier). En Python, ce qui est vide est faux, `0` est faux, `None` est faux, `False` est faux. Le reste est vrai : -```python +```pycon >>> bool("Non vide") True >>> bool([]) # Une liste vide @@ -930,7 +930,7 @@ Passer du temps sur la syntaxe et le vocabulaire ## Exemple -```python +```pycon >>> def temps_total(temps_de_preparation, temps_de_cuisson): ... return temps_de_preparation + temps_de_cuisson ... @@ -950,7 +950,7 @@ def fahrenheit_to_celsius(fahrenheit): ## Arguments On peut donc lui donner des arguments : -```python +```pycon >>> fahrenheit_to_celsius(320) 160.0 >>> fahrenheit_to_celsius(390) @@ -966,7 +966,7 @@ Exercices: First function, Print even numbers, ... # Les chaînes -```python +```pycon >>> """Elle préfère "l'huile d'olive".""" 'Elle préfère "l\'huile d\'olive".' ``` @@ -989,7 +989,7 @@ def une_fonction(): ## Les opérateurs mathématiques -```python +```pycon >>> 0.1 + 0.1 0.2 ``` @@ -997,7 +997,7 @@ def une_fonction(): ## Les opérateurs mathématiques -```python +```pycon >>> 0.1 + 0.2 0.30000000000000004 ``` @@ -1017,7 +1017,7 @@ l'élément suivant. Qu'on soit dans un `for` ou dans un `while`. ## `break` -```python +```pycon >>> while True: ... if not il_reste_de_la_pâte: ... break @@ -1028,7 +1028,7 @@ l'élément suivant. Qu'on soit dans un `for` ou dans un `while`. ## `continue` -```python-repl +```pycon-repl >>> for recette in recettes: ... if "sésame" in recette["ingredients"]: ... continue @@ -1043,7 +1043,7 @@ Houmous ## Les exceptions : `try` -```python +```pycon >>> try: ... int("2 kg") ... except ValueError: @@ -1056,7 +1056,7 @@ Raté C'est transformer ça : -```python +```pycon >>> durées = [] >>> for recette in recettes: ... durées.append(recette["durée"]) @@ -1069,7 +1069,7 @@ C'est transformer ça : en : -```python +```pycon >>> [recette["durée"] for recette in recettes] [35, 20, 13] ``` @@ -1114,20 +1114,20 @@ Elle devrait s'écrire sur une seule ligne, mais, vidéoprojecteur... *slices* en anglais +notes: + On pourrait traduire par « tranches » et filer la métaphore culinaire… -Notes: +['incontestable', 'contestable', 'testable', 'stable'] + ```python seq = 'incontestable' -# ['incontestable', 'contestable', 'testable', 'stable'] ``` - ## Les *slices* -```python ->>> seq -'incontestable' +```pycon +>>> seq = 'incontestable' >>> seq[0] 'i' ``` @@ -1135,65 +1135,79 @@ seq = 'incontestable' ## Les *slices* -```python +```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* -```python ->>> seq[3:6] -['D', 'E', 'F'] -``` - - -## Les *slices* - -```python ->>> seq[:] -['A', 'B', 'C', 'D', 'E', 'F'] -``` - - -## Les *slices* - -```python ->>> seq[1:] -['B', 'C', 'D', 'E', 'F'] -``` - - -## Les *slices* - -```python +```pycon >>> seq[-1] -'F' +'e' ``` ## Les *slices* -```python ->>> seq[:-2] -['A', 'B', 'C', 'D'] +```pycon +>>> seq[-6:] +'stable' ``` ## Les *slices* -```python ->>> seq[0:5:2] -['A', 'C', 'E'] +```pycon +>>> "perso"[::2] +'pro' ``` -## Les *slices* +notes: ```python ->>> seq[::-1] -['F', 'E', 'D', 'C', 'B', 'A'] +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 ``` @@ -1251,7 +1265,7 @@ Notes: On connaît les attributs. ## Exemple -```python +```pycon >>> ISIN = { ... "GLE": "FR0000130809", ... "PARRO": "FR0004038263", @@ -1296,7 +1310,7 @@ BiaisedDice(Dice) est un bon exemple d'héritage. ## Utilisation -```python +```pycon >>> dice = Dice() >>> dice.throw() >>> dice.value @@ -1306,7 +1320,7 @@ BiaisedDice(Dice) est un bon exemple d'héritage. ## Utilisation -```python +```pycon >>> cup = DiceCup( ... [Dice() for _ in range(10)] ... ) @@ -1517,7 +1531,7 @@ Notes: Voir mon bashrc :] Surtout "viable" depuis la 3.8. Signifie « plusieurs », comme dans une liste ou un *n*-uplet. -```python +```pycon >>> begin, *rest = range(5) >>> begin 0 @@ -1538,7 +1552,7 @@ begin, rest = seq[0], seq[1:] ## `*` -```python +```pycon >>> def sum(*args): ... print(args) ... @@ -1549,7 +1563,7 @@ begin, rest = seq[0], seq[1:] ## `*` -```python +```pycon >>> [0, 0, 0, *range(3)] [0, 0, 0, 0, 1, 2] ``` @@ -1557,7 +1571,7 @@ begin, rest = seq[0], seq[1:] ## `*` -```python +```pycon >>> print(*range(5)) 0 1 2 3 4 ``` @@ -1568,7 +1582,7 @@ begin, rest = seq[0], seq[1:] Signifie « plusieurs, nommés », comme dans un dictionnaire. -```python +```pycon >>> def p(**kwargs): ... for key, value in kwargs.items(): ... print(key, "→", value) @@ -1581,7 +1595,7 @@ y → 12 ## `**` -```python +```pycon >>> defaults = {"path": "./", ... "pattern": "*.txt"} >>> {**defaults, "pattern": "*.md"} @@ -1591,7 +1605,7 @@ y → 12 ## `**` -```python +```pycon >>> def p(x, y): ... print(f"x → {x}") ... print(f"y → {y}") @@ -1610,7 +1624,7 @@ y → 12 C'est transformer une chaîne en octets, pour son transport ou stockage : -```python +```pycon >>> "L'été".encode() b"L'\xc3\xa9t\xc3\xa9" >>> list("L'été".encode()) @@ -1622,7 +1636,7 @@ b"L'\xc3\xa9t\xc3\xa9" C'est le contraire ... -```python +```pycon >>> bytes([76, 39, 195, 169, 116, 195, 169]).decode() "L'été" ``` diff --git a/python-initiation/test.py b/python-initiation/test.py deleted file mode 100755 index 7d22261..0000000 --- a/python-initiation/test.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -from string import ascii_letters, digits -import re -import doctest -from tempfile import NamedTemporaryFile -import importlib.util - -parser = argparse.ArgumentParser() -parser.add_argument("file", nargs="+") -parser.add_argument("-v", "--verbose", action="store_true") -parser.add_argument("-d", "--debug", action="store_true") -args = parser.parse_args() - -for file_to_test in args.file: - with open(file_to_test) as f: - source = f.read() - - with NamedTemporaryFile(mode="w", suffix=".py") as f: - for example_match in re.finditer("```python.*?```", source, re.S): - example = example_match.group() - example = "\n".join(example.split("\n")[1:-1]) - lineno = source[:example_match.start()].count("\n") + 1 - function_name = ''.join(letter if letter in ascii_letters + digits else '_' for letter in file_to_test[:-3]) + "_line_" + str(lineno) - if example.startswith(">>> "): - if '"""' in example: - f.write(f"""def _{function_name}():\n r'''""" + example + """\n'''\n\n""") - else: - f.write(f'''def _{function_name}():\n r"""''' + example + '''\n"""\n\n''') - else: - f.write(example + "\n\n") - f.flush() - if args.debug: - with open(f.name) as py_source: - print(py_source.read()) - spec = importlib.util.spec_from_file_location("to_test", f.name) - to_test = importlib.util.module_from_spec(spec) - spec.loader.exec_module(to_test) - doctest.testmod(to_test, verbose=args.verbose) diff --git a/python-initiation/test.py b/python-initiation/test.py new file mode 120000 index 0000000..18c8c51 --- /dev/null +++ b/python-initiation/test.py @@ -0,0 +1 @@ +../python-avancé/test.py \ No newline at end of file