Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Licence CC BY-NC-ND Thierry Parmentelat & Arnaud Legout Inria - UCA

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 :

  1. paramètres positionnels (usuels)

  2. paramètres nommés (forme name=default)

  3. paramètres *args qui attrape dans un tuple le reliquat des arguments positionnels

  4. 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):
    pass

car é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 :