Skip to article frontmatterSkip to article content

le tutorial Python sur ce sujet occupe à lui tout seul deux chapitres: chapitre 10 et chapitre 11
le spectre est très très complet, je fais ici un tri totalement arbitraire...

logging

dans du code de production on ne fait jamais print() ! on utilise à la place logging, car de cette façon:

# voici comment configurer logging pour avoir un comportement 'à la' print

import logging
logging.basicConfig(level=logging.INFO)
# au lieu de faire 

print(f"Bonjour le monde")
Bonjour le monde
# on fera plutôt

logging.info("Bonjour le monde")
INFO:root:Bonjour le monde
# ou encore 

logging.error("OOPS")
ERROR:root:OOPS

sys et os

sont utilisés très fréquemment, surtout dans du code ancien, pour

from pathlib import Path

( import os.path)

historiquement on gérait les noms de fichiers sur disque avec le sous-module os.path
mais depuis la 3.4 une alternative orientée objet est disponible!

from pathlib import Path

for path in Path(".").glob("samples/*.py"):
    # le nom canonique
    print(10*'=', path.absolute())
    # le dernier morceau dans le nom
    print(path.name, end=' ')
    # la taille
    print(path.stat().st_size, 'bytes')
    # touver le nom absolu
    # ouvrir le fichier en lecture
    with path.open():
        pass
========== /home/runner/work/slides/slides/notebooks/samples/closures.py
closures.py 254 bytes
========== /home/runner/work/slides/slides/notebooks/samples/fact_sysargv.py
fact_sysargv.py 739 bytes
========== /home/runner/work/slides/slides/notebooks/samples/fact_argparse.py
fact_argparse.py 1286 bytes
========== /home/runner/work/slides/slides/notebooks/samples/typehints.py
typehints.py 173 bytes
========== /home/runner/work/slides/slides/notebooks/samples/fib.py
fib.py 307 bytes
========== /home/runner/work/slides/slides/notebooks/samples/fact_sysargv2.py
fact_sysargv2.py 532 bytes
# c'est très facile de se promener dans l'arbre des fichiers

répertoire = Path(".")
fichier = répertoire / "samples" / "fib.py"

with fichier.open() as feed:
    for lineno, line in enumerate(feed, 1):
        print(f"{lineno}:{line}", end="")
1:# un module définit souvent des fonctions et classes
2:
3:def fib(n):
4:    a, b = 0, 1
5:    while b < n:
6:        print(b, end=' ')
7:        a, b = b, a + b
8:
9:
10:# le code qui suit sera exécuté seulement si on le lance
11:# depuis la ligne de commande, et pas pendant un import
12:
13:if __name__ == '__main__':
14:    fib(40)

datetime, math et random

datetime

math

random

formats de fichier

json

csv

pickle

le module collections

une extension des objets built-in list, tuple, dict
la doc est ici, voici une petite sélection

collections.Counter()

à partir d’un itérable, construit un dictionnaire qui contient

from collections import Counter

cnt = Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])
cnt
Counter({'blue': 3, 'red': 2, 'green': 1})
isinstance(cnt, dict)
True
# par exemple pour compter les mots dans un texte

import re
words = re.findall(r'\w+', open('../data/hamlet.txt').read().lower())

Counter(words).most_common(10)
[('the', 1108), ('and', 920), ('to', 762), ('of', 699), ('you', 593), ('i', 587), ('a', 557), ('my', 506), ('it', 443), ('in', 426)]

collections.defaultdict()

from collections import defaultdict

# on va fabriquer un dict    word -> liste d'indices où il apparait
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]

# pour cela on indique que les valeurs sont des listes
d = defaultdict(list)

# si on écrit une clé qui n'est pas encore présente
# d[k] vaut alors list()
# c'est-à-dire une liste vide est crée automatiquement
for k, v in s:
    d[k].append(v)

sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

itertools - combinatoire

fournit les combinatoires communes

itertools - produit cartésien

from itertools import product
A = ['a', 'b', 'c']
B = [ 1, 2]

for x, y in product(A, B):
    print(x, y)
a 1
a 2
b 1
b 2
c 1
c 2

itertools - permutations

from itertools import permutations
C = ['a', 'b', 'c', 'd']

for tuple in permutations(C):
    print(tuple)
('a', 'b', 'c', 'd')
('a', 'b', 'd', 'c')
('a', 'c', 'b', 'd')
('a', 'c', 'd', 'b')
('a', 'd', 'b', 'c')
('a', 'd', 'c', 'b')
('b', 'a', 'c', 'd')
('b', 'a', 'd', 'c')
('b', 'c', 'a', 'd')
('b', 'c', 'd', 'a')
('b', 'd', 'a', 'c')
('b', 'd', 'c', 'a')
('c', 'a', 'b', 'd')
('c', 'a', 'd', 'b')
('c', 'b', 'a', 'd')
('c', 'b', 'd', 'a')
('c', 'd', 'a', 'b')
('c', 'd', 'b', 'a')
('d', 'a', 'b', 'c')
('d', 'a', 'c', 'b')
('d', 'b', 'a', 'c')
('d', 'b', 'c', 'a')
('d', 'c', 'a', 'b')
('d', 'c', 'b', 'a')

itertools - combinaisons

from itertools import combinations
miniloto = list(range(5))

for a, b in combinations(miniloto, 2):
    print(a, b)
0 1
0 2
0 3
0 4

1 2
1 3
1 4
2 3
2 4
3 4
# les arrangements ne sont pas disponibles tel-quel
# mais une possibilité est de générer toutes les permutations
# de chaque tirage dans les combinaisons

def arrangements(collection, n):
    for tuple_ in combinations(collection, n):
        yield from permutations(tuple_)

for t in arrangements(miniloto, 2):
    print(t)
(0, 1)
(1, 0)
(0, 2)
(2, 0)
(0, 3)
(3, 0)
(0, 4)
(4, 0)
(1, 2)
(2, 1)
(1, 3)
(3, 1)
(1, 4)
(4, 1)
(2, 3)
(3, 2)
(2, 4)
(4, 2)
(3, 4)
(4, 3)

module itertools - divers

module itertools - suite

from itertools import filterfalse
%timeit -n 100 for x in filterfalse(lambda x:x%2, range(10000)): pass
3.58 ms ± 1.01 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit -n 100 for x in (y for y in range(10000) if not (y % 2)): pass
1.11 ms ± 386 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)

operator

import random
l = [('a', random.randint(1, 1000)) for i in range(100)]
l.sort(key=lambda x: x[1])
l[-7:]
[('a', 956), ('a', 960), ('a', 960), ('a', 963), ('a', 965), ('a', 989), ('a', 996)]
l = [('a', random.randint(1, 1000)) for i in range(100)]
import operator
l.sort(key=operator.itemgetter(1))
l[-7:]
[('a', 937), ('a', 960), ('a', 960), ('a', 973), ('a', 974), ('a', 984), ('a', 992)]