Portée et lambdas
Comprenez la portée des variables et écrivez des fonctions inline concises.
- Comprendre la portée locale contre globale
- Utiliser les mots-clés global et nonlocal
- Écrire des fonctions lambda pour des opérations courtes
- Appliquer les lambdas avec sorted(), map(), filter()
Où vit un nom ?
Une variable est un nom relié à une valeur, mais où cette liaison tient, c’est la portée. Les mathématiques le marquent aussi : dans , la lettre est un marque-place qui ne vit qu’à l’intérieur de la définition. Hors de là, peut signifier tout autre chose. Python dessine les mêmes murs autour des corps de fonctions : une variable créée dans une fonction est locale, elle existe à l’intérieur des murs et nulle part ailleurs.
def my_func():
x = 10
print(x) # fonctionne
my_func()
# print(x) # NameError : x n'est pas définieLes variables définies au niveau du module, en revanche, sont visibles partout en dessous, elles sont globales :
counter = 0
def increment():
global counter
counter += 1
increment()
print(counter) # 1Le problème de global, c’est qu’il laisse une fonction réécrire le monde de l’intérieur. La liaison change là où rien dans l’appel ne vous avait annoncé qu’elle changerait. Préférez renvoyer des valeurs plutôt que d’atteindre global, une fonction qui renvoie est une fonction que vous pouvez tester et raisonner à l’isolement.
Portée imbriquée et nonlocal
Les fonctions peuvent s’imbriquer, et une fonction interne peut lire une variable externe. La réassigner, en revanche, exige le mot-clé nonlocal, un aveu que le nom appartient à la portée englobante :
def make_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
counter = make_counter()
print(counter()) # 1
print(counter()) # 2L’increment interne porte sa propre mémoire : chaque appel pousse le count capturé. C’est une fermeture, une fonction avec une poche d’état qu’elle traîne après que sa fonction englobante a fini.
Lambda : la fonction en ligne
Une fonction qui tient sur une ligne a une sténographie. lambda crée une petite fonction anonyme, une formule sous forme d’expression :
add = lambda a, b: a + b
print(add(3, 5)) # 8C’est l’équivalent du def que vous connaissez déjà :
def add(a, b):
return a + bLa différence est une question de poids : def écrit toute la cérémonie pour n’importe quoi avec des étapes ; lambda reste en ligne pour une seule expression, sans docstring plus tard, sans return, l’expression après les deux points est la valeur renvoyée.
Lambdas avec des fonctions d’ordre supérieur
Les lambdas gagnent leur vie lorsqu’elles sont données à des fonctions qui prennent une fonction en entrée. Trier par score, appliquer à chaque élément, garder ceux qui passent un test, chacune est la notation de construction d’ensembles en code :
students = [("Alice", 85), ("Bob", 92), ("Charlie", 78)]
# Tri par score (deuxième élément)
by_score = sorted(students, key=lambda s: s[1])
print(by_score) # [('Charlie', 78), ('Alice', 85), ('Bob', 92)]
# Map : appliquer une fonction à chaque élément — $\{2x \mid x \in \text{nums}\}$
nums = [1, 2, 3, 4]
doubled = list(map(lambda x: x * 2, nums))
# [2, 4, 6, 8]
# Filter : garder ceux qui passent un test — $\{x \in \text{nums} \mid x \equiv 0 \pmod{2}\}$
evens = list(filter(lambda x: x % 2 == 0, nums))
# [2, 4]map transforme chaque élément ; filter conserve les éléments qu’un prédicat approuve ; sorted ordonne selon une clé choisie. Trois opérations courantes sur les données, chacune acceptant une minuscule fonction comme bouton de personnalisation.
Un exemple travaillé : la fonction propre
Le conseil de la portée, préférer return à global, a une forme prête : un prix avec le taux comme paramètre :
def price_with_tax(price, rate=0.2):
return round(price * (1 + rate), 2)
price_with_tax(10.0) # 12.0
price_with_tax(10.0, 0.08) # 10.8La fonction propre n’a pas besoin de global : le taux arrive comme paramètre, le monde extérieur reste intact, et la formule se lit, . Tout se passe dans les murs, et le résultat revient par return.
Pièges courants
- Utiliser
globalquand unreturnsuffirait. Cela cache l’effet de bord et couple la fonction à son environnement. - Abuser des lambdas. Une seule expression ; dès qu’une lambda a besoin de deux étapes, faites-en un
def. - Confondre la portée dans les fonctions imbriquées. Quand une variable est lue, Python sort pour la chercher ; un cri
nonlocalouglobalchange qui peut l’écrire. Lisez cette logique avant de supposer la liaison. sortedsanskeytrie par l’élément lui-même. Les tuples se trient lexicographiquement par leur premier élément d’abord ; pour trier par le second, lakeyest obligatoire,sorted(students, key=lambda s: s[1]).
🧩 Défis
🧩 Défi, réfléchissez d'abord, puis révélez
Triez les mots words = ["banana", "pie", "Washington", "a"] par longueur.
💡 Réponse : sorted(words, key=lambda w: len(w)) → ['a', 'pie', 'banana', 'Washington'], la fonction clé élève chaque mot au nombre comparé.
🧩 Défi, réfléchissez d'abord, puis révélez
Utilisez filter avec une lambda pour conserver les mots de plus de trois caractères de ["hi", "hello", "hey", "howdy", "yo"].
💡 Réponse : list(filter(lambda w: len(w) > 3, words)) → ['hello', 'howdy'], le prédicat est votre condition d'appartenance, et filter est le constructeur d'ensemble.
🤔 Questions socratiques
- Pourquoi Python exige-t-il
nonlocalplutôt que de laisser les fonctions internes réassigner librement une variable externe ? Quelles erreurs l’exigence prévient-elle ? map/filteravec une lambda contre une compréhension de liste, quand chacune est-elle l’orthographe la plus claire ?- Une lambda n’accepte qu’une seule expression. Quelle limite se cache derrière cette règle ?
✅ Vérification rapide
1. Que renvoie sorted(["banana", "pie", "a"], key=len) ?
2. Quel mot-clé permet à une fonction interne de modifier une variable externe ?