# Python

Par

<!-- .slide: data-background="static/background.jpg" -->

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.

Et 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 : 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…

<img src="static/Black-hole-M87.jpg" style="width:60%">


## Combien ?

<a href="https://git.afpy.org/mdk/python-versions">
<img src="https://git.afpy.org/mdk/python-versions/media/branch/main/pypi-download-counts.png" style="width:90%">
</a>

::: notes

Oui ça fait ~175TB/jour sur PyPI.org.

https://insights.stackoverflow.com/trends baisse en 2023, pourquoi ?


## Quelle version ?

<a href="https://git.afpy.org/mdk/python-versions">
<img src="https://git.afpy.org/mdk/python-versions/media/branch/main/python-versions-lines.png" style="width:90%">
</a>


## 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 comparaisons


```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"} | {"œuf", "sucre"} == {"sucre","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'
```


# 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']
```

## 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
```
…


## 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 Recette:
    def __init__(self, nom, ingrédients):
        self.nom = nom
        self.ingrédients = ingrédients
```

Notes: On connaît les attributs.


## Exemple

```pycon
>>> ingrédients = {
...     'farine': 1000,
...     'eau': 615,
...     'levure': 10,
...     'sel': 20
... }
```

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 floats

@given(floats())
def test_temperature_conversions(temp):
    assert fahrenheit_to_celsius(
        celsius_to_fahrenheit(temp)) == temp

```


# 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.


## 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

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
>>> "Pâte à crêpe".encode()
b'P\xc3\xa2te \xc3\xa0 cr\xc3\xaape'
>>> list("Pâte à crêpe".encode())
[80, 195, 162, 116, 101, 32, 195, 160, 32, 99, 114, 195, 170, 112, 101]
```


## décoder

C'est le contraire ...

```pycon
>>> b'P\xc3\xa2te \xc3\xa0 cr\xc3\xaape'.decode()
'Pâte à crêpe'
```

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) ! Les meetups locaux !

- https://pycon.fr
- https://discuss.afpy.org/c/meetups/12
