Complément - niveau intermédiaire¶
Rappel¶
Nous avons vu dans un précédent complément les 4 familles de paramètres qu’on peut déclarer dans une fonction :
paramètres positionnels (usuels)
paramètres nommés (forme name=default)
paramètres *args qui attrape dans un tuple le reliquat des arguments positionnels
paramètres **kwds qui attrape dans un dictionnaire le reliquat des arguments nommés
Pour rappel :
# une fonction qui combine les différents
# types de paramètres
def foo(a, b=100, *args, **kwds):
print(f"a={a}, b={b}, args={args}, kwds={kwds}")foo(1)a=1, b=100, args=(), kwds={}
foo(1, 2)a=1, b=2, args=(), kwds={}
foo(1, 2, 3)a=1, b=2, args=(3,), kwds={}
foo(1, 2, 3, bar=1000)a=1, b=2, args=(3,), kwds={'bar': 1000}
Un seul paramètre attrape-tout¶
Notez également que, de bon sens, on ne peut déclarer qu’un seul paramètre de chacune des formes d’attrape-tout ; on ne peut pas par exemple déclarer
# c'est illégal de faire ceci
def foo(*args1, *args2):
passcar évidemment on ne saurait pas décider de ce qui va dans args1 et ce qui va dans args2.
Ordre des déclarations¶
L’ordre dans lequel sont déclarés les différents types de paramètres d’une fonction est imposé par le langage. Ce que vous avez peut-être en tête si vous avez appris Python 2, c’est qu’à l’époque on devait impérativement les déclarer dans cet ordre :
positionnels, nommés, forme
*, forme**
comme dans notre fonction foo.
Ça reste une bonne approximation, mais depuis Python-3, les choses ont un petit peu changé suite à l’adoption du PEP 3102, qui vise à introduire la notion de paramètre qu’il faut impérativement nommer lors de l’appel (en anglais : keyword-only argument)
Pour résumer, il est maintenant possible de déclarer des paramètres nommés après la forme *
Voyons cela sur un exemple
# on peut déclarer un paramètre nommé **après** l'attrape-tout *args
def bar(a, *args, b=100, **kwds):
print(f"a={a}, b={b}, args={args}, kwds={kwds}")L’effet de cette déclaration est que, si je veux passer un argument au paramètre b, je dois le nommer
# je peux toujours faire ceci
bar(1)a=1, b=100, args=(), kwds={}
# mais si je fais ceci l'argument 2 va aller dans args
bar(1, 2)a=1, b=100, args=(2,), kwds={}
# pour passer b=2, je **dois** nommer mon argument
bar(1, b=2)a=1, b=2, args=(), kwds={}
Ce trait n’est objectivement pas utilisé massivement en Python, mais cela peut être utile de le savoir :
en tant qu’utilisateur d’une bibliothèque, car cela vous impose une certaine façon d’appeler une fonction ;
en tant que concepteur d’une fonction, car cela vous permet de manifester qu’un paramètre optionnel joue un rôle particulier.