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:
le code a seulement à choisir un niveau de message parmi
exception,error,warning,info,debugon pourra choisir plus tard (i.e. par l’équipe Ops) :
si on veut les messages (avec quel niveau de gravité, et depuis quels modules)
où doivent aller les messages (
/var/log, syslog, stdout, ...)
# 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
import sysgestions de variables utilisées par l’interpréteur
e.g.
sys.path, et plein plein d’autres dans ce module un peu fourre-tout
import osaccès cross-platform au système d’exploitation
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¶
gestion des dates et des heures
math¶
fonctions mathématiques, constantes, ...
random¶
générations de nombres et séquences aléatoires, mélange aléatoire de séquences
formats de fichier¶
json¶
sérialisation d’objets python, standard du web
envoi et réception depuis toutes sources compatibles json
csv¶
ouverture fichier csv, compatible Excel et tableurs
pickle¶
sérialisation d’objets python, uniquement compatible avec python
sauvegarde et la chargement du disque dur
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
comme clefs les éléments uniques
et comme valeurs le nombre de fois que l’élément apparaît
from collections import Counter
cnt = Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])
cntCounter({'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()¶
étend les dictionnaires pour en faciliter l’initialisation
https://
docs .python .org /3 /library /collections .html ? #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¶
implémente sous forme efficace (itérateurs)
des combinatoires classiques
et autres outils utiles pour écrire des boucles concises
déjà abordé dans la partie 3.3 sur les itérateurs
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¶
parfois sans fin
count(10) --> 10 11 12 13 14 ...cycle('abcd') --> a b c d a b c d ...
ou pas
islice('abcdefg', 2, none) --> c d e f grepeat(10, 3) --> 10 10 10
module itertools - suite¶
chainer plusieurs itérations
chain('ABC', 'DEF') --> A B C D E Fchain.from_iterable(['ABC', 'DEF']) --> A B C D E F
avec un peu de logique
takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1compress('ABCDEF', [1,0,1,0,1,1]) --> A C E Ffilterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8
from itertools import filterfalse%timeit -n 100 for x in filterfalse(lambda x:x%2, range(10000)): pass3.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)): pass1.11 ms ± 386 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)
operator¶
en python tout est un objet, on peut donc tout passer à une fonction, mais comment passer un opérateur comme
+,in, ou>le module
operatorcontient la version fonctionnelle d’un grand nombre d’opérateurs python
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)]