Skip to article frontmatterSkip to article content

est-ce vraiment utile d’expliquer les affectations (en anglais assignment) ?
étonnamment il y a un million de choses à dire sur les multiples formes de l’affectation !

affectation simple

bon à la base c’est simple; cette affectation est une instruction

a = 'alice'
print(a)
alice

portée des variables (intermédiaire)

pour faire court, la portée d’une variable est la fonction - et non pas, comme dans les langages à la C++, le bloc (c’est d’ailleurs assez cohérent avec le fait qu’il n’y a pas de {} en Python, si on veut)

à savoir également, l’affectation sert aussi de déclaration: si vous affectez une variable dans une fonction, cela signifie que la variable est locale à la fonction

global et nonlocal

ces deux mots-clé permettent d’affecter une variable qui justement n’est pas locale à la fonction:
global pour référencer une variable globale au module,
nonlocal pour référencer une variable dans une fonction imbriquée entre le module et la fonction courante

# exemple avec global
variable = 1

def foo():
    global variable
    # no worries this time
    print(f"inside {variable=}")
    variable = 2

print(f"before {variable=}")
foo()
# variable is 2
print(f"outside {variable=}")
before variable=1
inside variable=1
outside variable=2

affectation par unpacking

une forme très fréquente - et très pratique - d’affectation
on “déballe” le contenu d’une structure, et on affecte les morceaux à plusieurs variables d’un coup

a, b, c = ['alice', 'bob', 'charlie']
print(b)
bob

il y a bien sûr quelques contraintes

extended unpacking

L = [1, 2, 3, 4, 5]
a, *b = L
print(f"{a=} {b=}")
a=1 b=[2, 3, 4, 5]
a, *b, c, d = L
print(f"{a=} {b=} {c=} {d=}")
a=1 b=[2, 3] c=4 d=5

unpacking - ignorer des valeurs avec _

# je ne garde pas les valeurs à la 2e et 4e position
debut, _, milieu, _, fin = [1, 2, 3, 4, 5] 
print(f"{debut=} {fin=} {_=}")
debut=1 fin=5 _=4

unpacking et imbrications

un peu plus gadget, mais parfois utile:

# le \ c'est juste pour aligner les deux morceaux
obj = \
1, ( (2, 3), (4, [5, 6])), 6
a, ( _,      [b,  c    ]), d = obj
print(f"{a=} {b=} {c=} {d=}")
a=1 b=4 c=[5, 6] d=6

affectation multiple

# une seule liste
a = b = c = [1, 2, 3]
a is b
True
# qui donne un résultat très différent de ceci où on crée deux listes
A = [1, 2, 3]
B = [1, 2, 3]
A is B
False
# dans la pratique c'est surtout utilisé en conjonction avec le unpacking

L = car, *cdr = [1, 2, 3]
print(f"{L=} {car=} {cdr=}")
L=[1, 2, 3] car=1 cdr=[2, 3]

affectation et boucle for

pour anticiper un peu sur les boucles for, l’affectation a lieu aussi à chaque itération de boucle

liste = [1, 10, 100]

for item in liste:
    print(f"{item=}", end=" ")
item=1 item=10 item=100 
# du coup dans un for on peut aussi faire du unpacking

liste = ([1, 2], [10, 20], [100, 200])

for a, b in liste:
    print(f"{a=}x{b=}", end=" ")
a=1xb=2 a=10xb=20 a=100xb=200 

expression d’affectation (walrus)

enfin depuis la 3.8 on dispose aussi d’une expression qui fait de l’affectation
bon c’est un peu plus limité que l’instruction (pas de unpacking, pas de seq[i] ou de var.attribut dans la partie gauche)
mais ça rend parfois service:

# exemple 1 : lecture d'un fichier par buffer

CHUNK = 20 * 1024

with open("../data/hamlet.txt") as feed:
    while chunk := feed.read(CHUNK):
        print(f"[{len(chunk)}]", end='')
[20480][20480][20480][20480][20480][20480][20480][20480][15005]
# exemple 2 : les regexps

import re
pattern = r"(\d+)(st|nd|rd|th) edition"

with open("../data/hamlet.txt") as feed:
    for lineno, line in enumerate(feed, 1):
        if match := re.search(pattern, line):
            print(match.group(0))
3rd edition