Python - Comprendre args, kwargs dans les fonctions

Logo

Introduction

En débutant en Python, on rencontre des exemples de code avec les syntaxes suivantes :

def log_error(self, msg, *args, **kwargs)
  • Habitué à Javascript, PHP…, on se demande : *args, **kwargs, c’est quoi ça ?
  • Habitué des langages C ou Go, on se demande : *args, **kwargs, des pointeurs en Python ?

*args et **kwargs permettent de passer de multiples arguments et des arguments nommés à une fonction. Expliquons *args et **kwargs à travers des exemples simples.

Une simple fonction qui retourne une somme, args

argkarg.py
def sum(x,y):
	return x + y

print(sum(1,2))
$ python3 argkarg.py
3

Cette fonction fonctionne à merveille si il n’y a que 2 arguments entiers. *args est utilisé pour spécifier de multiples arguments :

argkarg.py
def sum(*args):
	r = 0
	for x in args:
		r += x
	
	return r

print(sum(10,20,30,40))
100

args est juste un nom, un autre nom peut être utilisé :

def sum(*listint):
	r = 0
	for x in listint:
    …

L’opérateur * est important ici. args dans la fonction est alors un objet de type tuple, ce n’est pas un objet list. Les objets de type tuple sont immutables, les valeurs ne peuvent plus être modifiées après définition.

def sum(*args):

  print(args)
  print(type(args))

  r = 0
  for x in args:
		r += x
	
  return r

print(sum(10,20,30,40))
(10, 20, 30, 40)
<class 'tuple'>
100

Utiliser également l’opérateur * si les valeurs des arguments sont stockées dans des objets list ou tuple :

l = [10,20,30,40]
print(sum(*l))

t = [100,200,300,400]
print(sum(*t))
100
1000

kwargs dans les fonctions

**kwargs fonctionne comme *args mais pour les arguments nommés (kw pour keyword).

def sum(**kwargs):
	r = 0
	for x in kwargs.values():
		r += x
	
	return r

print(sum(a=10,b=20,c=30,d=40))
100

Comme args, kwargs est juste un nom, il peut être différent.

L’opérateur ** conduit à un dictionnaire, mutable. kwargs est un dictionnaire :

def sum(**kwargs):
	print(kwargs)
	print(type(kwargs))

	r = 0
	for x in kwargs.values():
		r += x
	
	return r

print(sum(a=10,b=20,c=30,d=40))
<class 'dict'>
{'a': 10, 'b': 20, 'c': 30, 'd': 40}
100

Combiner args et kwargs, ordre des arguments

L’ordre des arguments est important dans la déclaration de la fonction lorsque *args et **kwargs sont à la fois utilisés :

  1. Arguments réguliers
  2. Arguments *args
  3. Arguments **kwargs
def sum(x,y,*args,**kwargs):
	
	r=0
	r = x + y

	for i in args:
		r += i
	
	for i in kwargs.values():
		r += i
	
	return r

print(sum(1,2,3,4,a=10,b=20,c=30,d=40))110

Une erreur "Invalid syntax" est levée lorsque l’ordre n’est pas le bon :

def sum(x,y,**kwargs,*args):
  …
  File "argkarg.py", line 15
    def sum(x,y,**kwargs,*args):
                          ^
SyntaxError: invalid syntax

Les opérateurs * et ** (unpacking operators)

L’opérateur * défait les objets itérables : listes, tuples

l = [1,2,3]
print(*l)

t = (1,2,3)
print(*t)
1 2 3
1 2 3

Cet opérateur * est très utile pour fusionner des listes et/ou des tuples, un exemple :

t1 = (1,2,3)
t2 = (4,5)
l1 = [6,7]

t3 = (*t1,*t2,*l1)
l2 = [*t1,*t2,*l1]
print(t3)
print(l2)
(1, 2, 3, 4, 5, 6, 7)
[1, 2, 3, 4, 5, 6, 7]

L’opérateur ** défait les dictionnaires, utile pour fusionner des dictionnaires :

d1 = { 'a' : 10, 'b' : 20 }
d2 = { 'c' : 30, 'd' : 40 }
d3 = { **d1, **d2 }

print(d3)
{'a': 10, 'b': 20, 'c': 30, 'd': 40}