print(x) chasse fixe, gras : code à taper tel quelnom italique : valeur à remplacer→ 42 résultat obtenu, vérifié en exécutant l’exemple⏎ retour à la ligne dans ce qui est affiché| python | ouvrir l’interpréteur interactif ; Windows : aussi py ; Linux, macOS : souvent python3 |
| python prog.py | exécuter un programme |
| python -i prog.py | exécuter, puis rester dans l’interpréteur pour inspecter les variables |
| python -m module | lancer un module : pip, venv, http.server… |
| python -c "code" | exécuter une seule ligne |
| python -V | afficher la version installée |
| exit() | quitter l’interpréteur ; 3.13+ exit suffit ; ou Ctrl+D (Windows : Ctrl+Z puis Entrée) |
| Windows : gestionnaire d’installation 3.14+ | |
| py install 3.14 | installer une version |
| py list | lister les versions installées |
| py -V:3.14 prog.py | lancer avec une version précise |
| py help | toutes les commandes |
L’installateur Windows classique est déprécié depuis 3.14 ; il ne sera plus produit à partir de 3.16.
>>> invite ; ... suite d’un bloc — une ligne vide le termine._ rappelle le dernier résultat affiché.help(len) · help("for") : aide ; dir(x) : attributs de x ; type(x) : son type."""Aire d'un disque.""" 1 import math 2 RAYON = 2.5 3 def aire(r): 4 """Renvoie l'aire du disque.""" return math.pi * r ** 2 5 if __name__ == "__main__": 6 print(f"{aire(RAYON):.2f}") → 19.63
help() ;def, nom, paramètres, deux-points ;: et se délimite par l’indentation : 4 espaces, sans mélange avec des tabulations.; final.# commente jusqu’à la fin de la ligne.( ), [ ] ou { } plutôt qu’avec \.nom ≠ Nom.pass : bloc vide, à compléter plus tard.Une variable est un nom attaché à un objet. Le type appartient à l’objet, pas au nom : c’est le typage dynamique.
| age = 36 | créer, ou réaffecter |
| a, b = 1, 2 | (1, 2) affectation multiple |
| a, b = b, a | (2, 1) échange, sans variable temporaire |
| x = y = 0 | (0, 0) même valeur |
| x += 5 | 5 équivaut à x = x + 5 ; de même -= *= /=… |
| type(3.5) | <class 'float'> type de l’objet |
isinstance(5, int) → True test de type | |
| del x | supprimer le nom |
| nombre_total | variable, fonction : snake_case |
| CompteBancaire | classe : CapWords |
| TAUX_MAX | constante |
| _interne | usage interne (convention) |
| __init__ | méthode spéciale, dite « dunder » |
| _ | valeur ignorée : for _ in range(3): |
Un nom : lettres, chiffres et _, sans chiffre en tête ni mot réservé.
| Valeurs | False None True |
| Logique | and or not is in |
| Conditions | if elif else |
| Boucles | for while break continue |
| Fonctions | def return lambda yield global nonlocal |
| Classes | class |
| Exceptions | try except finally raise assert |
| Modules | import from as |
| Divers | with pass del |
| Asynchrone | async await |
| Contextuels | match case _ type réservés selon le contexte |
| Arithmétique | |
| 7 / 2 | 3.5 division : toujours un float |
| 7 // 2 | 3 division entière (quotient) |
| -7 // 2 | -4 ! arrondi vers le bas |
| 7 % 3 | 1 reste (modulo) |
| 2 ** 10 | 1024 puissance |
| -2 ** 2 | -4 ! ** passe avant le signe |
| Comparaison et logique | |
| 3 == 3.0 | True égalité de valeur |
| 0 < 5 <= 10 | True comparaisons enchaînées |
| x is None | True identité : pour None |
| "ch" in "chat" | True appartenance |
| not 0 | True négation |
| 0 or "défaut" | 'défaut' 1er opérande vrai |
| "" and 1 / 0 | '' court-circuit : 1 / 0 jamais évalué |
| Bit à bit | |
6 & 3, 6 | 3, 6 ^ 3 → (2, 7, 5) et, ou, ou exclusif | |
| 1 << 4, ~5 | (16, -6) décalage, inversion |
( ) › ** › +x -x ~x › * / // % › + - › << >> › & › ^ › | › == < in is… › not › and › or › a if c else b › lambda › :=Dans le doute : des parenthèses. 2 + 3 * 4 → 14 ; (2 + 3) * 4 → 20.
nom, age = "Alice", 36
print("Bonjour", nom)
→ Bonjour Alice
print(nom, age, sep=" | ")
→ Alice | 36
print(f"{nom} a {age} ans")
→ Alice a 36 ans
print(f"{age=}") → age=36
print("fin", end="!\n") → fin!texte = input("Âge ? ") # une chaîne
age = int(texte) # conversioninput() renvoie du texte : convertir avec int() ou float() avant de calculer.
Valent faux : False, None, 0, 0.0, "", [], (), {}, set(), range(0). Tout le reste vaut vrai.
| bool([]) | False liste vide |
| bool("0") | True ! chaîne non vide |
| bool(" ") | True ! une espace n’est pas rien |
D’où l’usage : if liste: plutôt que if len(liste) > 0:
| int | 42 -7 1_000_000 0xFF 0b1010 — entiers, sans limite de taille |
| float | 3.14 1e-3 float("inf") — à virgule flottante, ≈ 15 chiffres significatifs |
| complex | 2+3j — z.real, z.imag |
| bool | True False — sous-type de int |
| str | 'a' "a" """a""" — texte Unicode, immuable |
| bytes | b"abc" — octets bruts (fichiers binaires, réseau) |
| NoneType | None — absence de valeur |
2 ** 100 → 1267650600228229401496703205376 | |
0xFF, 0b1010, 1_000 → (255, 10, 1000) hexadécimal, binaire, séparateur | |
| True + True | 2 True vaut 1 |
| abs(-3.5) | 3.5 valeur absolue |
| divmod(17, 5) | (3, 2) quotient, reste |
| round(3.14159, 2) | 3.14 |
round(2.5), round(3.5) → (2, 4) ! arrondi au pair le plus proche | |
| max(3, 7, 1) | 7 et min |
| sum([1, 2, 3]) | 6 |
| pow(2, 10, 1000) | 24 210 modulo 1000 |
Module math (import math) | |
math.sqrt(2) → 1.4142135623730951 | |
math.floor(-2.5), math.ceil(2.1) → (-3, 3) vers le bas, vers le haut | |
math.gcd(12, 18), math.lcm(4, 6) → (6, 12) PGCD, PPCM | |
math.factorial(5), math.comb(5, 2) → (120, 10) 5 !, combinaisons | |
math.log10(1000), math.log2(8) → (3.0, 3.0) logarithmes ; math.log(x) : népérien | |
math.dist((0, 0), (3, 4)) → 5.0 distance | |
| math.pi · math.e · math.inf | constantes |
0.1 + 0.2 → 0.30000000000000004 0.1 + 0.2 == 0.3 → False ! import math math.isclose(0.1 + 0.2, 0.3) → True from decimal import Decimal Decimal("0.1") + Decimal("0.2") → Decimal('0.3') from fractions import Fraction Fraction(1, 3) + Fraction(1, 6) → Fraction(1, 2)
Les float sont stockés en binaire : 0,1 n’y a pas de valeur exacte. Comparer avec math.isclose ; pour de l’argent, Decimal construit à partir d’une chaîne (Decimal(0.1) hérite de l’erreur).
| "l'été" · 'dit "oui"' | guillemets simples ou doubles, au choix |
| """…""" | chaîne sur plusieurs lignes |
| \n \t \\ \" \u00e9 | saut de ligne, tabulation, \, ", caractère par son code (é) |
| r"C:\temp\new" | chaîne brute : \ non interprété (chemins Windows, expressions régulières) |
| "ab" + "cd" | 'abcd' concaténation |
| "ab" * 3 | 'ababab' répétition |
| len("été") | 3 longueur en caractères |
| "Z" < "a" | True ! ordre des codes : majuscules d’abord |
| s[0] = "J" | TypeError immuable : on crée une nouvelle chaîne |
Elles renvoient une nouvelle chaîne : s.upper() ne modifie pas s.
| "été".upper() | 'ÉTÉ' aussi lower() |
"le petit prince".title() → 'Le Petit Prince' | |
"bonjour".capitalize() → 'Bonjour' | |
| " a b ".strip() | 'a b' aussi lstrip, rstrip |
"a,b,,c".split(",") → ['a', 'b', '', 'c'] | |
"un deux\ttrois".split() → ['un', 'deux', 'trois'] sans argument : tout blanc | |
" - ".join(["a", "b", "c"]) → 'a - b - c' inverse de split | |
"chat".replace("a", "o") → 'chot' | |
| "banane".count("an") | 2 |
| "banane".find("n") | 2 -1 si absent |
| "banane".index("z") | ValueError si absent |
"img.png".endswith(".png") → True et startswith | |
"img.png".removesuffix(".png") → 'img' 3.9+ et removeprefix | |
"clé=val".partition("=") → ('clé', '=', 'val') | |
| "7".zfill(3) | '007' |
"titre".center(9, "*") → '**titre**' et ljust, rjust | |
| "123".isdigit() | True et isalpha, isspace… |
| "Straße".casefold() | 'strasse' comparer sans la casse |
| int("42") | 42 |
| int(3.99) | 3 troncature vers zéro |
| int("ff", 16) | 255 lecture en base 16 |
| float("2.5") | 2.5 |
| float("2,5") | ValueError ! virgule décimale refusée |
| int("abc") | ValueError texte non numérique |
| str(42) | '42' |
ord("é"), chr(65) → (233, 'A') code Unicode ↔ caractère | |
| hex(255), bin(5) | ('0xff', '0b101') |
| list("abc") | ['a', 'b', 'c'] |
f"{ valeurexpression!rconversion: >10.2fformat}" Après :, dans l’ordre : remplissage, alignement (< ^ >), signe, largeur, séparateur (, ou _), précision (.2), type (f d % e x b).
| f"{x:.2f}" | '3.14' 2 décimales |
| f"{x:8.3f}" | ' 3.142' largeur 8 |
| f"{n:,}" | '1,234,567' milliers |
f"{n:,}".replace(",", " ") → '1 234 567' à la française | |
| f"{0.256:.1%}" | '25.6%' pourcentage |
| f"{42:05d}" | '00042' zéros en tête |
| f"{nom:<6}|" | 'Ada |' à gauche |
| f"{nom:>6}|" | ' Ada|' à droite |
| f"{nom:*^7}" | '**Ada**' centré, remplissage |
f"{255:x}", f"{5:08b}" → ('ff', '00000101') hexadécimal, binaire | |
| f"{nom!r}" | "'Ada'" avec repr() |
| f"{x=:.1f}" | 'x=3.1' débogage 3.8+ |
| f"{{x}}" | '{x}' accolades littérales |
Anciennes syntaxes, encore rencontrées : "{:.2f}".format(x) et "%.2f" % x. 3.14+ t"…" crée un gabarit (Template), pas une chaîne : il sert aux bibliothèques qui doivent traiter les valeurs insérées.
str : des caractères ; fichiers et réseau : des octets (bytes).
| "é".encode("utf-8") | b'\xc3\xa9' texte → octets |
b"\xc3\xa9".decode("utf-8") → 'é' octets → texte | |
len("é"), len("é".encode()) → (1, 2) 1 caractère, 2 octets | |
| "\u00e9" == "e\u0301" | False ! é précomposé ≠ e + accent |
unicodedata.normalize("NFC", "e\u0301") == "é" → True normaliser avant de comparer | |
| Type | Écriture | Ordre | Modif. | Doubl. |
|---|---|---|---|---|
| list | [1, 2, 2] | oui | oui | oui |
| tuple | (1, 2, 2) | oui | non | oui |
| dict | {"a": 1} | oui* | oui | clés : non |
| set | {1, 2} | non | oui | non |
| str | "abc" | oui | non | oui |
* ordre d’insertion, garanti depuis 3.7. Modif. : modifiable ; Doubl. : doublons admis. frozenset : ensemble non modifiable, donc hachable.
! {} est un dict vide ; ensemble vide : set(). Tuple d’un seul élément : (1,) — c’est la virgule qui fait le tuple.
Chaque ligne part de L = [3, 1, 4].
| L.append(1) | [3, 1, 4, 1] ajouter à la fin |
L.extend([5, 9]) → [3, 1, 4, 5, 9] ajouter plusieurs | |
| L.insert(0, 7) | [7, 3, 1, 4] insérer à l’indice 0 |
| L.pop() | 4 retire et renvoie le dernier |
| L.pop(0) | 3 … ou celui de l’indice 0 |
| L.remove(1) | [3, 4] 1re occurrence ; ValueError si absente |
| L[1] = 9 | [3, 9, 4] remplacer |
| del L[0] | [1, 4] supprimer par indice |
| L[1:] = [] | [3] remplacer une tranche |
| L.index(4) | 2 position |
| L.sort() | [1, 3, 4] tri sur place, renvoie None |
| sorted(L) | [1, 3, 4] nouvelle liste, L intacte |
L.sort(reverse=True) → [4, 3, 1] ordre décroissant | |
| L.reverse() | [4, 1, 3] inverser |
| L = L.sort() | None ! piège classique |
| L + [1, 5] | [3, 1, 4, 1, 5] concaténer |
| [0] * 3 | [0, 0, 0] |
4 in L, len(L), sum(L) → (True, 3, 8) et min, max | |
| L.copy() | [3, 1, 4] copie (ou L[:]) |
mots = ["Kiwi", "ail", "pomme", "figue"] sorted(mots) # A-Z avant a-z → ['Kiwi', 'ail', 'figue', 'pomme'] ! sorted(mots, key=str.lower) → ['ail', 'figue', 'Kiwi', 'pomme'] sorted(mots, key=len) → ['ail', 'Kiwi', 'pomme', 'figue']
Le tri est stable : à clé égale, l’ordre d’origine est conservé (pomme avant figue).
Chaque ligne part de d = {"a": 1, "b": 2}.
| d["a"] | 1 lire |
| d["z"] | KeyError ! clé absente |
| d.get("z") | None sans erreur |
| d.get("z", 0) | 0 valeur par défaut |
d["c"] = 3 → {'a': 1, 'b': 2, 'c': 3} ajoute ou remplace | |
| del d["a"] | {'b': 2} |
| d.pop("a") | 1 retire et renvoie |
| "a" in d | True teste les clés |
| list(d) | ['a', 'b'] les clés |
| list(d.values()) | [1, 2] |
list(d.items()) → [('a', 1), ('b', 2)] | |
| d | {"b": 9} | {'a': 1, 'b': 9} fusion 3.9+ |
d.update(c=3) → {'a': 1, 'b': 2, 'c': 3} fusion sur place | |
d.setdefault("l", []).append(5) → {'a': 1, 'b': 2, 'l': [5]} crée si absent | |
dict(zip("xy", [1, 2])) → {'x': 1, 'y': 2} à partir de deux listes | |
dict.fromkeys("xy", 0) → {'x': 0, 'y': 0} | |
| {[1]: "x"} | TypeError ! une liste ne peut être clé |
for cle, valeur in d.items():
print(cle, valeur) → a 1 ⏎ b 2Clés : objets hachables, donc immuables (str, int, tuple…).
Avec a = {1, 2, 3} et b = {3, 4} :
| a | b | {1, 2, 3, 4} union |
| a & b | {3} intersection |
| a - b | {1, 2} différence |
| a ^ b | {1, 2, 4} différence symétrique |
| {1, 2} <= a | True inclusion |
| a.add(9) | {1, 2, 3, 9} ajouter |
| a.discard(7) | {1, 2, 3} retirer sans erreur |
| a.remove(7) | KeyError si absent |
| set([3, 1, 3, 2]) | {1, 2, 3} dédoublonner |
list(dict.fromkeys([3, 1, 3])) → [3, 1] … en gardant l’ordre | |
Pas d’indice, ordre non garanti ; éléments hachables seulement.
Les indices désignent les bords des cases ; comptés depuis la fin, ils sont négatifs. Syntaxe : s[début:fin:pas], fin exclue.
| s[0] | 'P' premier |
| s[-1] | 'N' dernier |
| s[1:4] | 'YTH' de 1 inclus à 4 exclu |
| s[:2] | 'PY' les 2 premiers |
| s[2:] | 'THON' à partir de l’indice 2 |
| s[-3:] | 'HON' les 3 derniers |
| s[::2] | 'PTO' un sur deux |
| s[::-1] | 'NOHTYP' à l’envers |
| s[10] | IndexError ! hors limites… |
| s[2:10] | 'THON' … mais une tranche tolère |
Valable pour toute séquence : chaînes, listes, tuples.
point = (3, 4) x, y = point # déballage x → 3 premier, *reste = [1, 2, 3, 4] reste → [2, 3, 4] *debut, dernier = "abc" debut → ['a', 'b'] a, _ = (10, "x") # _ : ignoré def bornes(L): return min(L), max(L) # un tuple bas, haut = bornes([4, 1, 7]) bas, haut → (1, 7)
[x * 2expressionfor x in Lboucleif x > 0]filtre (facultatif)[x ** 2 for x in range(5)] → [0, 1, 4, 9, 16] [x for x in range(10) if x % 3 == 0] → [0, 3, 6, 9] [x if x > 0 else 0 for x in [-2, 5, -1]] → [0, 5, 0] {m: len(m) for m in ["un", "deux"]} → {'un': 2, 'deux': 4} {x % 3 for x in range(10)} → {0, 1, 2} sum(x ** 2 for x in range(4)) → 14 [f"{i}{j}" for i in "ab" for j in "12"] → ['a1', 'a2', 'b1', 'b2']
if après for : filtre. … if … else … avant for : transforme chaque élément. Sans crochets, entre parenthèses : une expression génératrice, calculée à la demande, sans liste en mémoire.
a = [1, 2] b = a # deux noms, UN objet b.append(3) a → [1, 2, 3] ! c = a.copy() # ou list(a), a[:] c == a, c is a → (True, False) m = [[0] * 2] * 2 # 2 fois la même ligne m[0][0] = 1 m → [[1, 0], [1, 0]] ! # correct : une ligne par tour m = [[0] * 2 for _ in range(2)] import copy m2 = copy.deepcopy(m) # copie profonde
== compare les valeurs, is l’identité. Immuables : int, float, str, tuple, frozenset, bytes. Modifiables : list, dict, set, la plupart des objets. copy() ne copie qu’un niveau.
note = 13
if note >= 16:
mention = "très bien"
elif note >= 14:
mention = "bien"
elif note >= 12:
mention = "assez bien"
else:
mention = "aucune"
mention → 'assez bien'
age = 20
s = "majeur" if age >= 18 else "mineur"
s → 'majeur'| if x: | x non vide, non nul |
| if not liste: | liste vide |
| if x is None: | jamais == None |
| if 0 <= n < 10: | encadrement |
| if rep in ("o", "oui"): | plusieurs valeurs |
| if isinstance(x, (int, float)): | type |
def analyser(cmd):
match cmd.split():
case ["aller", direction]:
return f"vers {direction}"
case ["prendre", *obj]:
return f"{len(obj)} objets"
case ["quitter" | "q"]:
return "fin"
case [n] if n.isdigit():
return f"code {n}"
case _:
return "inconnu"
analyser("aller nord") → 'vers nord'
analyser("prendre a b") → '2 objets'
analyser("q") → 'fin'
analyser("42") → 'code 42'
analyser("") → 'inconnu'case 0:, alternative |, capture x, séquence [a, *reste], dictionnaire {"type": t}, classe Point(x=0), garde if.case _: attrape tout le reste.case ROUGE: attrape tout. Comparer à une constante : nom pointé, case Couleur.ROUGE:mots = "un deux trois quatre".split() # affecte n, puis le compare if (n := len(mots)) > 3: print(n, "mots") → 4 mots
Utile dans while (ligne := f.readline()): ; à réserver aux cas où il évite une répétition.
while True:
texte = input("Note (0-20) ? ")
try: # voir page 7
note = int(texte)
except ValueError:
print("Un entier, svp.")
continue # redemander
if 0 <= note <= 20:
break # valide
print("Hors limites.")for lettre in "abc":
print(lettre, end=" ") → a b c| list(range(5)) | [0, 1, 2, 3, 4] 5 exclu |
| list(range(2, 6)) | [2, 3, 4, 5] |
list(range(0, 10, 3)) → [0, 3, 6, 9] pas de 3 | |
list(range(3, 0, -1)) → [3, 2, 1] à rebours | |
list(enumerate("ab", 1)) → [(1, 'a'), (2, 'b')] numéro + élément | |
list(zip("ab", [1, 2, 3])) → [('a', 1), ('b', 2)] s’arrête au plus court ; strict=True 3.10+ : erreur si longueurs différentes | |
list(reversed([1, 2, 3])) → [3, 2, 1] | |
any(x > 2 for x in [1, 3]) → True au moins un | |
all(x > 2 for x in [1, 3]) → False tous | |
list(map(str.upper, "ab")) → ['A', 'B'] appliquer | |
list(filter(str.isdigit, "a1b2")) → ['1', '2'] filtrer | |
max(["kiwi", "ananas"], key=len) → 'ananas' selon un critère |
noms = ["Ana", "Léo"]
notes = [15, 12]
for nom, note in zip(noms, notes):
print(nom, note) → Ana 15 ⏎ Léo 12n = 0 while n < 3: # tant que c'est vrai n += 1 # sinon : sans fin n → 3 for x in [4, 9, 15, 7]: if x % 2 == 0: continue # tour suivant if x > 10: break # sortie de boucle print(x) → 9 else: print("fini") # si aucun break
while True: … if condition: break.KeyboardInterrupt).for x in L[:]) ou construire une nouvelle liste.| x == 1 or 2 | 2 ! toujours vrai ! → x in (1, 2) |
list(range(1, 4)) → [1, 2, 3] fin exclue : 1 à 10 → range(1, 11) | |
| 0.1 + 0.2 == 0.3 | False ! flottants : math.isclose |
| for i in range(len(L)): | fonctionne, mais for x in L: ou enumerate(L) est plus clair |
if x = 5: → SyntaxError : = affecte, == compare.
L = [3, 1, 3, 2]
d = {"a": 3, "b": 7, "c": 5}
M = [[1, 2], [3, 4]]
# compter les occurrences
from collections import Counter
Counter("abracadabra").most_common(2)
→ [('a', 5), ('b', 2)]
# clé de la plus grande valeur
max(d, key=d.get) → 'b'
# trier un dict par valeur
sorted(d.items(), key=lambda kv: kv[1])
→ [('a', 3), ('c', 5), ('b', 7)]
# inverser un dict
{v: k for k, v in d.items()}
→ {3: 'a', 7: 'b', 5: 'c'}
# aplatir une liste de listes
[x for ligne in M for x in ligne]
→ [1, 2, 3, 4]
# transposer une matrice
list(zip(*M)) → [(1, 3), (2, 4)]
# dédoublonner en gardant l'ordre
list(dict.fromkeys(L)) → [3, 1, 2]
# compter à la main
cpt = {}
for c in "abca":
cpt[c] = cpt.get(c, 0) + 1
cpt
→ {'a': 2, 'b': 1, 'c': 1}
# indice du maximum
L.index(max(L)) → 0
# découper en paquets (3.12+)
from itertools import batched
list(batched("abcde", 2))
→ [('a', 'b'), ('c', 'd'), ('e',)]notes = [12, 8, 15, 9] total = 0 # accumulateur for n in notes: total += n total → 44 nb = 0 # compteur for n in notes: if n >= 10: nb += 1 nb → 2 m = None # meilleur vu for n in notes: if m is None or n > m: m = n m → 15
Formes courtes : sum(notes), sum(n >= 10 for n in notes), max(notes).
it = iter([10, 20]) next(it), next(it) → (10, 20) next(it) → StopIteration def rebours(n): # génératrice while n > 0: yield n # donne, attend n -= 1 list(rebours(3)) → [3, 2, 1] # expression génératrice : # rien n'est calculé d'avance carres = (x * x for x in range(10**9)) next(carres), next(carres) → (0, 1)
for appelle iter(), puis next() jusqu’à StopIteration. Un générateur fournit ses valeurs à la demande : mémoire constante, mais un seul parcours. yield from autre délègue à un autre itérable.
def prix_ttc(ht, taux=0.20): 1 """Renvoie le prix TTC arrondi au centime.""" 2 return round(ht * (1 + taux), 2) 3 prix_ttc(100) → 120.0 prix_ttc(100, 0.055) → 105.5 prix_ttc(taux=0.1, ht=50) → 55.0
def, nom, paramètres ; taux a une valeur par défaut ;help(prix_ttc) ;return renvoie la valeur et termine la fonction ; sans return, elle renvoie None.À l’appel : arguments positionnels (par rang) d’abord, puis nommés (taux=0.1), dans n’importe quel ordre.
def f(a, b=2, *args, c, d=4, **kwargs):
return a, b, args, c, d, kwargs
f(1, c=3) → (1, 2, (), 3, 4, {})
f(1, 5, 6, 7, c=3, e=8) → (1, 5, (6, 7), 3, 4, {'e': 8})
nombres, options = [1, 5], {"c": 3}
f(*nombres, **options) → (1, 5, (), 3, 4, {})
f(1) → TypeError !| a | positionnel ou nommé |
| b=2 | valeur par défaut |
| *args | positionnels en surplus, reçus dans un tuple |
| c, d=4 | après *args (ou un * seul) : nommés obligatoirement |
| **kwargs | nommés en surplus, reçus dans un dict |
| def g(x, /, y): | x positionnel uniquement 3.8+ |
| def h(x, *, y): | y nommé uniquement |
| f(*liste, **dico) | à l’appel : déballer une liste, un dict |
Un nom est cherché dans l’ordre Local → fonction Englobante → Global (module) → Built-in (fonctions natives) : règle LEGB.
compteur = 0
def incrementer():
global compteur # sans cela : UnboundLocalError
compteur += 1
incrementer()
compteur → 1
def fabrique():
total = 0
def ajouter(n):
nonlocal total # variable de la fonction englobante
total += n
return total
return ajouter # une « fermeture » (closure)
acc = fabrique()
acc(5), acc(3) → (5, 8)Préférer paramètres et valeurs de retour à global : le code reste lisible et testable.
import math # puis : math.sqrt(2) from math import sqrt, pi # puis : sqrt(2) import datetime as dt # alias : dt.date(2026, 1, 15)
.py : import outils charge outils.py ; un paquet est un dossier de modules.from module import * : on ne sait plus d’où viennent les noms.random.py, csv.py…) : il masque le vrai.if __name__ == "__main__": protège le code à n’exécuter qu’au lancement direct (page 1).sys.path.double = lambda x: 2 * x # fonction anonyme double(4) → 8 mots = ["kiwi", "Ail", "banane"] sorted(mots, key=str.lower) → ['Ail', 'banane', 'kiwi'] sorted(mots, key=lambda m: m[-1]) → ['banane', 'kiwi', 'Ail'] ops = {"+": lambda a, b: a + b, "*": lambda a, b: a * b} ops["*"](3, 4) → 12
Une fonction est un objet : on peut la ranger dans une variable, un dict, la passer en argument. PEP 8 : lambda pour une expression courte passée en argument, def sinon.
def ajouter(x, L=[]): # liste créée UNE fois L.append(x) return L ajouter(1) → [1] ajouter(2) → [1, 2] ! def ajouter(x, L=None): # la bonne forme if L is None: L = [] # nouvelle liste à chaque appel L.append(x) return L ajouter(1), ajouter(2) → ([1], [2])
La valeur par défaut est évaluée une seule fois, à la définition de la fonction.
def factorielle(n):
if n <= 1: # cas de base : indispensable
return 1
return n * factorielle(n - 1)
factorielle(5) → 120
import sys
sys.getrecursionlimit() → 1000Au-delà de la limite (1 000 appels imbriqués par défaut) : RecursionError. Une boucle est souvent plus sûre.
import functools, time
def chronometrer(f):
@functools.wraps(f) # conserve nom et docstring
def enveloppe(*args, **kwargs):
t0 = time.perf_counter()
resultat = f(*args, **kwargs)
duree = time.perf_counter() - t0
print(f"{f.__name__} : {duree:.3f} s")
return resultat
return enveloppe
@chronometrer # somme = chronometrer(somme)
def somme(n):
return sum(range(n))
@functools.cache # mémorise les résultats
def fib(n):
return n if n < 2 else fib(n - 1) + fib(n - 2)
fib(80) → 23416728348467685Un décorateur prend une fonction et en renvoie une autre qui l’enveloppe : chronométrer, journaliser, mettre en cache, contrôler l’accès. @functools.lru_cache(maxsize=128) : cache de taille bornée.
def moyenne(notes: list[float]) -> float:
return sum(notes) / len(notes)
moyenne([12.0, 15.0]) → 13.5
age: int = 36
nom: str | None = None # « ou » entre types (3.10+)
type Point = tuple[float, float] # alias de type (3.12+)
moyenne("abc") → TypeErrorPython ne vérifie pas les annotations à l’exécution (l’erreur ci-dessus vient de sum) : elles documentent et servent aux outils externes (mypy, pyright) et aux éditeurs.
class Compte:
"""Compte bancaire simple."""
nb_comptes = 0 # attribut de classe
def __init__(self, titulaire, solde=0):
self.titulaire = titulaire # attributs d'instance
self.solde = solde
Compte.nb_comptes += 1
def deposer(self, montant): # méthode
if montant <= 0:
raise ValueError("montant positif attendu")
self.solde += montant
return self.solde
def __repr__(self): # affichage technique
return f"Compte({self.titulaire!r}, {self.solde})"
c = Compte("Alice", 100) # crée l'objet, puis appelle __init__
c.deposer(50) → 150
c.solde → 150
c → Compte('Alice', 150)
Compte.nb_comptes → 1| classe | le modèle : Compte |
| instance, objet | un exemplaire : c |
| attribut | une donnée de l’objet : c.solde |
| méthode | une fonction de la classe : c.deposer(50) équivaut à Compte.deposer(c, 50) |
| self | l’instance concernée ; premier paramètre de chaque méthode (nom conventionnel) |
| __init__ | initialise l’objet juste après sa création |
| _solde · __solde | usage interne (convention) · nom « brouillé » en _Compte__solde |
class CompteEpargne(Compte): # hérite de Compte def __init__(self, titulaire, solde=0, plafond=10_000): super().__init__(titulaire, solde) # le parent d'abord self.plafond = plafond def deposer(self, montant): # redéfinition if self.solde + montant > self.plafond: raise ValueError("plafond dépassé") return super().deposer(montant) e = CompteEpargne("Bob", 9_900) e.deposer(50) → 9950 e.deposer(100) → ValueError: plafond dépassé isinstance(e, Compte) → True [k.__name__ for k in CompteEpargne.__mro__] → ['CompteEpargne', 'Compte', 'object']
super() appelle la version de la classe parente, selon l’ordre de résolution des méthodes (__mro__). Héritage = relation « est un » ; pour « a un », préférer la composition : un attribut qui contient un autre objet.
| type(42) | <class 'int'> classe de l’objet |
| isinstance(True, int) | True tient compte de l’héritage |
| hasattr("", "upper") | True possède cet attribut ? |
| getattr(3, "real", None) | 3 attribut par son nom, avec défaut |
| callable(len) | True appelable ? |
| dir(x) · vars(x) · id(x) | attributs · dict des attributs · identité |
Typage canard : peu importe la classe d’un objet, pourvu qu’il possède les méthodes attendues.
from enum import Enum, auto
class Couleur(Enum):
ROUGE = auto()
VERT = auto()
Couleur.VERT → <Couleur.VERT: 2>
Couleur.VERT.name → 'VERT'
Couleur(1) → <Couleur.ROUGE: 1>
[c.name for c in Couleur] → ['ROUGE', 'VERT']class Temperature:
def __init__(self, celsius):
self.celsius = celsius # passe par le setter
@property # lecture : t.celsius
def celsius(self):
return self._celsius
@celsius.setter # écriture
def celsius(self, valeur):
if valeur < -273.15:
raise ValueError("sous le zéro absolu")
self._celsius = valeur
@property
def fahrenheit(self): # attribut calculé
return self._celsius * 9 / 5 + 32
@classmethod # autre constructeur
def depuis_fahrenheit(cls, f):
return cls((f - 32) * 5 / 9)
@staticmethod # ni self ni cls
def gele(celsius):
return celsius <= 0
Temperature(25).fahrenheit → 77.0
Temperature.depuis_fahrenheit(212).celsius → 100.0
Temperature.gele(-3) → True
Temperature(-300) → ValueError: sous le zéro absoluElles branchent un objet sur la syntaxe du langage.
| __init__(self, …) | C(…) : initialisation |
| __repr__(self) | repr(x), interpréteur : non ambigu |
| __str__(self) | str(x), print(x) : lisible |
| __eq__(self, o) | x == y |
| __lt__(self, o) | x < y, donc sorted() |
| __hash__(self) | clé de dict, élément de set |
| __len__(self) | len(x) |
| __bool__(self) | if x: |
| __getitem__(self, i) | x[i] |
| __contains__(self, v) | v in x |
| __iter__(self) | for v in x: |
| __add__(self, o) | x + y ; aussi __sub__, __mul__… |
| __call__(self, …) | x(…) : objet appelable |
| __enter__, __exit__ | with x: : gestionnaire de contexte |
from dataclasses import dataclass, field, asdict @dataclass(frozen=True) # frozen : immuable, hachable class Point: x: float y: float = 0.0 p = Point(1.5) p → Point(x=1.5, y=0.0) p == Point(1.5, 0) → True asdict(p) → {'x': 1.5, 'y': 0.0} p.x = 2 → FrozenInstanceError ! @dataclass(order=True) # order : <, >, sorted() class Tache: priorite: int titre: str = "" tags: list[str] = field(default_factory=list) sorted([Tache(2, "b"), Tache(1, "a")])[0].titre → 'a'
@dataclass écrit pour vous __init__, __repr__ et __eq__. Valeur par défaut modifiable : field(default_factory=list).
def diviser(texte):
try:
n = int(texte) # peut lever ValueError
r = 100 / n # peut lever ZeroDivisionError
except ValueError:
print("pas un entier")
except ZeroDivisionError as e: # e : l'objet exception
print("erreur :", e)
else: # seulement si aucune exception
print("résultat :", r)
finally: # dans tous les cas
print("fin")
diviser("4") → résultat : 25.0 ⏎ fin
diviser("0") → erreur : division by zero ⏎ fin
diviser("x") → pas un entier ⏎ finclass SoldeInsuffisant(Exception): # exception personnalisée """Le solde ne couvre pas le retrait.""" def retirer(solde, montant): if montant > solde: raise SoldeInsuffisant(f"il manque {montant - solde} €") return solde - montant try: retirer(50, 70) except SoldeInsuffisant as e: print("Refusé :", e) → Refusé : il manque 20 €
except: nu, qui avale tout, même Ctrl+C.raise seul, dans un except : relance l’exception en cours ; raise Autre("…") from e : nouvelle exception, cause conservée.except (ValueError, TypeError): plusieurs types ; 3.14+ parenthèses facultatives sans as.assert x > 0, "message" : contrôle de développement, ignoré avec python -O.BaseException
+-- KeyboardInterrupt Ctrl+C
+-- SystemExit sys.exit()
+-- Exception celles qu'on attrape
+-- ArithmeticError
| +-- ZeroDivisionError
+-- LookupError
| +-- IndexError indice hors limites
| +-- KeyError clé absente
+-- NameError
| +-- UnboundLocalError
+-- ImportError
| +-- ModuleNotFoundError
+-- OSError système, fichiers
| +-- FileNotFoundError
| +-- PermissionError
+-- RuntimeError
| +-- RecursionError
+-- AttributeError, TypeError, ValueError…except LookupError: attrape à la fois IndexError et KeyError.
def moyenne(notes):
return sum(notes) / len(notes)
print(moyenne([]))Traceback (most recent call last):
File "moyenne.py", line 3, in <module>
print(moyenne([]))
~~~~~~~^^^^
File "moyenne.py", line 2, in moyenne
return sum(notes) / len(notes)
~~~~~~~~~~~^~~~~~~~~~~~
ZeroDivisionError: division by zero~ et ^ soulignent l’expression fautive 3.11+.Chemin du fichier abrégé ; la dernière ligne se copie telle quelle dans un moteur de recherche.
SyntaxError: expected ':' | deux-points oublié après if, for, def… |
IndentationError: expected an indented block… | bloc non indenté ; tabulations et espaces mélangés |
NameError: name 'nmbre' is not defined | faute de frappe, variable jamais définie, import oublié |
TypeError: can only concatenate str (not "int") to str | convertir : str(36), ou une f-string |
TypeError: 'NoneType' object is not subscriptable | une fonction a renvoyé None |
ValueError: invalid literal for int() with base 10: '12,5' | texte non convertible |
IndexError: list index out of range | indice ≥ len(L) |
KeyError: 'nom' | clé absente : d.get("nom") |
AttributeError: 'list' object has no attribute 'push' | méthode inexistante : dir(x) |
UnboundLocalError: cannot access local variable 'x'… | affectation dans la fonction : global ou paramètre |
FileNotFoundError: [Errno 2] No such file or directory: 'absent.txt' | chemin relatif au dossier courant (Path.cwd()) |
ModuleNotFoundError: No module named 'paquet_absent' | non installé dans cet environnement : python -m pip install … |
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9… | mauvais encodage : préciser encoding= |
# écrire : le fichier est créé, ou ÉCRASÉ s'il existe with open("notes.txt", "w", encoding="utf-8") as f: f.write("12\n") print("15", file=f) # print vers un fichier # ajouter à la fin with open("notes.txt", "a", encoding="utf-8") as f: f.write("18\n") # lire ligne à ligne ; fermeture automatique en fin de bloc with open("notes.txt", encoding="utf-8") as f: notes = [int(ligne) for ligne in f] notes → [12, 15, 18]
"r" lecture (défaut)"w" écriture, écrase !"a" ajout en fin"x" création seule"rb" "wb" binairef.read() tout le textef.readline() ligne suivantef.readlines() liste des lignesf.write(s) sans \n ajoutéprint(…, file=f) avec \nToujours préciser encoding="utf-8" : jusqu’à 3.14, le défaut sous Windows dépend du système (souvent cp1252) ; UTF-8 devient le défaut avec Python 3.15 (PEP 686).
from pathlib import Path
p = Path("donnees") / "notes.txt" # / assemble les chemins
p.name, p.stem, p.suffix → ('notes.txt', 'notes', '.txt')
p.parent.name → 'donnees'
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text("12\n15\n", encoding="utf-8") → 6
p.read_text(encoding="utf-8").split() → ['12', '15']
p.exists() → True
[f.name for f in Path("donnees").glob("*.txt")] → ['notes.txt']Aussi : Path.cwd() dossier courant, Path.home() dossier personnel, p.resolve() chemin absolu, rglob("*.py") recherche récursive, p.rename(q), p.unlink() suppression !. Sous Windows : Path(r"C:\Users\…") ou barres obliques "C:/Users/…".
| python -m venv .venv | créer l’environnement du projet (une fois) |
.venv\Scripts\activate activer : Windows (PowerShell : Activate.ps1) | |
| source .venv/bin/activate | activer : Linux, macOS |
| deactivate | désactiver |
| python -m pip install paquet | installer depuis PyPI |
| pip install -U paquet | mettre à jour |
| pip list · pip show paquet | paquets installés · détails |
| pip freeze > requirements.txt | figer les versions |
| pip install -r requirements.txt | réinstaller à l’identique |
python -m pip installe pour ce Python-là, sans ambiguïté.Get-Help about_Execution_Policies.| os · sys | système : os.environ, sys.argv, sys.exit() |
| pathlib · shutil · zipfile | chemins ; copier, déplacer des dossiers ; archives |
| datetime · time · zoneinfo | dates, durées, pauses (time.sleep), fuseaux |
| math · random · statistics | calcul, hasard, moyenne, médiane, écart type |
| decimal · fractions | calcul exact |
| collections · itertools · functools | structures et outils d’itération, voir ci-dessous |
| re | expressions régulières |
| json · csv · tomllib | formats de données (TOML : 3.11+) |
| sqlite3 | base de données SQL dans un simple fichier |
| logging | journal d’exécution, au lieu de print |
| argparse | options de la ligne de commande |
| subprocess | lancer d’autres programmes |
| urllib.request | requêtes HTTP simples |
| unittest · doctest | tests automatiques |
| secrets · hashlib | jetons sûrs ; empreintes (hachage) |
| tkinter | interfaces graphiques simples |
! random ne convient pas à la sécurité : pour un mot de passe ou un jeton, secrets.
import json
d = {"nom": "Élise", "notes": [12, 15]}
s = json.dumps(d, ensure_ascii=False)
s
→ '{"nom": "Élise", "notes": [12, 15]}'
json.loads(s) == d → True
with open("d.json", "w",
encoding="utf-8") as f:
json.dump(d, f, ensure_ascii=False,
indent=2)
with open("d.json",
encoding="utf-8") as f:
d = json.load(f)
import csv
with open("n.csv", "w", newline="",
encoding="utf-8") as f:
w = csv.writer(f, delimiter=";")
w.writerow(["nom", "note"])
w.writerow(["Élise", 15])
with open("n.csv", newline="",
encoding="utf-8") as f:
lignes = list(csv.DictReader(
f, delimiter=";"))
lignes[0]
→ {'nom': 'Élise', 'note': '15'}JSON ↔ Python : objet ↔ dict, tableau ↔ list, true / null ↔ True / None. CSV : tout est lu comme texte ('15') ; newline="" obligatoire. Excel en français attend souvent ; et lit mieux les accents en encoding="utf-8-sig".
from collections import Counter Counter([1, 2, 2, 3, 2]).most_common(1) → [(2, 3)] from collections import defaultdict groupes = defaultdict(list) groupes["a"].append(1) # clé créée dict(groupes) → {'a': [1]} from collections import deque q = deque([1, 2], maxlen=3) q.appendleft(0) q.append(3) # 3 au plus q → deque([1, 2, 3], maxlen=3) q.popleft() → 1 from itertools import combinations list(combinations("abc", 2)) → [('a', 'b'), ('a', 'c'), ('b', 'c')] from itertools import permutations len(list(permutations("abcd"))) → 24 from itertools import product list(product([0, 1], repeat=2)) → [(0, 0), (0, 1), (1, 0), (1, 1)] from itertools import accumulate list(accumulate([1, 2, 3, 4])) → [1, 3, 6, 10]
from datetime import date, datetime from datetime import timedelta d = date(2026, 1, 15) d + timedelta(days=30) → datetime.date(2026, 2, 14) (date(2026, 12, 25) - d).days → 344 d.weekday() → 3 d.strftime("%d/%m/%Y") → '15/01/2026' d.isoformat() → '2026-01-15' datetime.strptime("15/01/2026 14:30", "%d/%m/%Y %H:%M") → datetime.datetime(2026, 1, 15, 14, 30)
weekday() : lundi = 0. date.today(), datetime.now() : aujourd’hui, maintenant. Codes : %Y année, %m mois, %d jour, %H %M %S heure, minute, seconde, %A nom du jour (anglais par défaut).
Fuseaux : ZoneInfo("Europe/Paris") du module zoneinfo ; sous Windows, installer d’abord le paquet tzdata.
. tout caractère\d chiffre\w lettre, chiffre, _\s blanc[aeiou] l’un de[^0-9] sauf* 0 ou plus+ 1 ou plus? 0 ou 1{2,4} de 2 à 4^ $ début, fin\b limite de mot( ) groupe| ou*? non gourmand\. point littéralimport re re.findall(r"\d+", "a1b22c333") → ['1', '22', '333'] re.sub(r"\s+", " ", "a b\t c") → 'a b c' motif = r"(\d\d)/(\d\d)/(\d{4})" m = re.search(motif, "le 15/01/2026") m.group(3) → '2026' bool(re.fullmatch(r"[A-Z]\d+", "B123")) → True
Toujours des chaînes brutes r"…". search cherche partout, match au début, fullmatch sur toute la chaîne.
| breakpoint() | pause dans le débogueur : n ligne suivante, s entrer, c continuer, p x afficher, q quitter |
| python -m pdb prog.py | déboguer dès la première ligne |
| print(f"{x=}") | affichage de débogage |
| python -m unittest | lancer les tests unittest |
| python -m pytest | lancer les tests pytest (paquet tiers) |
| python -m timeit "sum(range(1000))" | mesurer une durée |
logging.basicConfig(level=logging.INFO) journal avec niveaux | |
# fichier test_calcul.py # lancer : python -m pytest from calcul import moyenne def test_moyenne(): assert moyenne([10, 20]) == 15
snake_case pour variables et fonctions, CapWords pour les classes, MAJUSCULES pour les constantes.is None plutôt que == None ; if liste: plutôt que if len(liste) > 0:with pour les fichiers ; f-strings pour mettre en forme.import this : les principes de Python (PEP 20).