Des arguments par défaut définis à l'appel ?

En Python les valeurs des arguments par défaut sont définis à la création de la fonction, et non à l’appel, et c’est parfois bien :

SENTINEL = object()

def work(arg=SENTINEL):
    if arg is SENTINEL:
        print("No argument has been given.")
    else:
        print("Argument has been given and is:", arg)

De cette manière si on passe None, qui pourrait être une valeur légitime dans un certain contexte, alors on est toujours capable de savoir si l’utilisateur n’a rien donné, ou s’il a donné None, par exemple.

Mais c’est parfois surprenant, et on s’est tous fait mordre en mettant une valeur modifiable en argument par défaut…

La PEP 671 propose une syntaxe pour indiquer qu’une valeur (d’un argument par défaut) doit être construite à chaque appel, plutôt qu’une fois pour toutes à la définition de la fonction.

Ça économisera beaucoup de :

if the_arg is None:
    the_arg = its_default_mutable_value

et en plus d’économiser des lignes, ça rendra les prototypes plus vrais: au lieu de voir None on verra la bonne valeur dans le prototype de la fonction, c’est toujours sympa.

Et en dehors du côté verbeux et des deux lignes économisées, ça pourrait même être utilisé dans tout un tat d’autres contextes, l’exemple typique dans la lib bisect:

def bisect(a, x, lo=0, hi=None):

hi ne vaut pas vraiment None par défaut, mais len(a), c’est tentant de chercher une syntaxe pour exprimer ça, comme (mais attention c’est pas ça) :

def bisect(a, x, lo=0, hi=len(a)):

Le jeu : essayez de deviner quelle syntaxe pourrait convenir avant de lire la PEP :wink:

Trop cool cette PEP, c’est un vrai bon sujet. Quelque chose de similaire que j’aimerais beaucoup voir, c’est un mot clef lazy, comme dans Swift et d’autres.

Par contre on ajoute encore une nouvelle notation à Python ; le language perd vraiment de sa mythique simplicité ces temps-ci, et je ne comprends pas cette direction de nos chers mainteneurs. :frowning:

1 « J'aime »

Pour l’instant à la lecture des emails j’ai cru comprendre que => avait le dessus.
J’ai lu aussi des =: mais ça me paraît trop perturbant en symétrie avec :=.

J’ai vu une proposition à base de defer (qui revient au lazy expliqué par @ramnes) et ça me semblerait un bon compromis : une syntaxe plus longue pour ne la réserver qu’aux cas qui en ont réellement besoin et qui garde toute sa lisibilité.

L’avantage de ce genre de syntaxe plus verbeuse c’est qu’elle pourrait potentiellement être utilisable dans d’autres contextes plus tard ?