Une fonction en python aura cette forme ci
Copier le code
1 2 def add(a, b): return a + b
Si on part de cette fonction tout simple d'addition, on se rend vite compte de ses limites. Elle ne peut pas prendre plusieurs paramètres. Pour faire cela on est obligé de modifier la signature de la fonction
Copier le code
1 2 def add(a, b, c): return a + b + c
C'est une solution peu dynamique.
Nous allons donc voir comment faire cela tout en ayant un code python souple
Les paramètres positionnels : *args
On les trouve souvent sous *args dans la littérature même si ce n'est qu'une convention. On peut leur donner le nom que vous préférez (même si je vous conseille fortement de respecter la convention), il faut juste conserver le *
Ce caractère n'est pas un pointeur, c'est une déstructuration de liste que l'on nomme unpack
Copier le code
1 2 3 4 5 >>> a = [1, 2, 3] >>> print(*a) 1 2 3 >>> print(a) [1, 2, 3]
Dans cet exemple il prend les valeurs de cette liste pour les passer en paramètre de la fonction print()
D'ailleurs si on regarde la doc de cette fonction on se rend compte qu'elle est compatible avec l'unpacking de liste
Copier le code
1 2 3 4 5 >>> help(print) Help on built-in function print in module builtins: print(*args, sep=' ', end='\n', file=None, flush=False) ...
On va appliquer ce concept sur notre fonction d'addition
Copier le code
1 2 3 4 5 6 7 >>> def add(*args): ... print(args) ... >>> add(1, 2) (1, 2) >>> add(1, 2, 3) (1, 2, 3)
On se rend compte que notre fonction s'adapte à ces paramètres sans se crasher (je n'ai pas implémenté la logique d'addition mais vous avez compris le concept)
Les paramètres nommés : **kwargs
On voit également **kwargs dans la littérature même si ce n'est qu'une convention. On peut leur donner le nom que vous préférez (même si je vous conseille fortement de respecter la convention), il faut juste conserver le **
C'est une déstructuration de dictionnaire que l'on nomme unpack
On garde le même principe que sur les paramètres positionnels mais cette fois sur notre fonction on doit nommer le nom du paramètre
Copier le code
1 2 3 4 5 6 7 >>> def add(**kwargs): ... print(kwargs) ... >>> add(a=1, b=2) {'a': 1, 'b': 2} >>> add(a=1, b=2, c=3) {'a': 1, 'b': 2, 'c': 3}
Et les deux
On peut évidemment combiner les 2 types de paramètres, mais on doit impérativement les mettre dans un ordre précis. Les paramètres positionnels et ensuite les paramètres nommés
Copier le code
1 2 3 4 5 6 7 8 9 10 >>> def add(*args, **kwargs): ... print(args, kwargs) ... >>> add(0, a=1, b=2) (0,) {'a': 1, 'b': 2} >>> add(a=0, 1) File "<python-input-12>", line 1 add(a=0, 1) ^ SyntaxError: positional argument follows keyword argument
C'est une solution très souple lorsqu'on ne connaît pas à l'avance les paramètres de la fonction.
Quand l'utiliser ?
En cas d'absolue nécessité, car cela alourdit le code. On ne peut pas, au 1er coup d'œil, voir ce qu'attend la fonction : on doit aller regarder son contenu et lire attentivement la documentation.
D'ailleurs si vous l'utilisez mettez une docstring avec des exemples
J'utilise très souvent l'unpacking de liste sur des fonctions helpers pour faire de la construction de chaîne de caractères ou indirectement comme cela
Copier le code
1 logger.info("My message %s %s", (a, b))
Ou encore du unpacking de dictionnaire pour injecter mes données dans un objet
pydantic
Copier le code
1 2 data = {"name": "David", "zip", "63"} MyPydanticObject(**data)