Python Language Argument par défaut mutable


Exemple

def foo(li=[]):
    li.append(1)
    print(li)

foo([2])
# Out: [2, 1]
foo([3])
# Out: [3, 1]

Ce code se comporte comme prévu, mais si on ne passe pas un argument?

foo()
# Out: [1] As expected...

foo()
# Out: [1, 1]  Not as expected...

En effet, les arguments par défaut des fonctions et des méthodes sont évalués au moment de la définition plutôt que lors de l'exécution. Nous n'avons donc qu'une seule instance de la liste li .

La manière de le contourner est d'utiliser uniquement des types immuables pour les arguments par défaut:

def foo(li=None):
    if not li:
        li = []
    li.append(1)
    print(li)

foo()
# Out: [1]

foo()
# Out: [1]

Bien que ce soit une amélioration et même if not li correctement évaluée à False , de nombreux autres objets le font également, comme les séquences de longueur nulle. Les arguments suivants peuvent entraîner des résultats inattendus:

x = []
foo(li=x)
# Out: [1]

foo(li="")
# Out: [1]

foo(li=0) 
# Out: [1]

L'approche idiomatique consiste à vérifier directement l'argument contre l'objet None :

def foo(li=None):
    if li is None:
        li = []
    li.append(1)
    print(li)

foo()
# Out: [1]