Quiconque bricole avec Python depuis assez longtemps a été mordu (ou déchiré en morceaux) par le problème suivant:
def foo(a=[]):
a.append(5)
return a
Novices Python s'attendent cette fonction pour revenir toujours une liste avec un seul élément: [5]
. Le résultat est au contraire très différent, et très étonnant (pour un novice):
>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()
Un de mes directeurs a eu sa première rencontre avec cette fonctionnalité et l'a qualifiée de "faille de conception dramatique" du langage. J'ai répondu que le comportement avait une explication sous-jacente, et c'est en effet très déroutant et inattendu si vous ne comprenez pas les internes. Cependant, je n'ai pas pu répondre (à moi-même) à la question suivante: quelle est la raison de la liaison de l'argument par défaut à la définition de la fonction, et non à l'exécution de la fonction? Je doute que le comportement expérimenté ait une utilité pratique (qui a vraiment utilisé des variables statiques en C, sans multiplier les bugs?)
Modifier :
Baczek en a fait un exemple intéressant. Avec la plupart de vos commentaires et Utaal en particulier, j'ai développé davantage:
>>> def a():
... print("a executed")
... return []
...
>>>
>>> def b(x=a()):
... x.append(5)
... print(x)
...
a executed
>>> b()
[5]
>>> b()
[5, 5]
Pour moi, il semble que la décision de conception était relative à l'endroit où mettre la portée des paramètres: à l'intérieur de la fonction ou "ensemble" avec elle?
Faire la liaison à l'intérieur de la fonction signifierait qu'elle x
est effectivement liée à la valeur par défaut spécifiée lorsque la fonction est appelée, non définie, quelque chose qui présenterait un défaut profond: la def
ligne serait "hybride" dans le sens où une partie de la liaison (de l'objet fonction) se produirait à la définition, et une partie (affectation des paramètres par défaut) au moment de l'appel de la fonction.
Le comportement réel est plus cohérent: tout de cette ligne est évalué lorsque cette ligne est exécutée, c'est-à-dire lors de la définition de la fonction.
[5]
" Je suis un novice Python, et je ne m'attendrais pas à cela, car évidemment, foo([1])
je reviendrai [1, 5]
, non [5]
. Ce que vous vouliez dire, c'est qu'un novice s'attendrait à ce que la fonction appelée sans paramètre revienne toujours [5]
.