1542 votes

Utilisation de *args et **kwargs

J'ai donc des difficultés avec le concept de *args y **kwargs .

Jusqu'à présent, j'ai appris que :

  • *args = liste d'arguments - en tant qu'arguments positionnels
  • **kwargs = dictionnaire - dont les clés deviennent des arguments de mots-clés distincts et les valeurs deviennent des valeurs de ces arguments.

Je ne comprends pas en quoi cette tâche de programmation serait utile.

Peut-être :

Je pense entrer des listes et des dictionnaires comme arguments d'une fonction ET en même temps comme joker, donc je peux passer N'IMPORTE QUEL argument ?

Existe-t-il un exemple simple pour expliquer comment *args y **kwargs sont utilisés ?

De plus, le tutoriel que j'ai trouvé utilisait juste le "*" et un nom de variable.

Sont *args y **kwargs juste des emplacements ou utilisez-vous exactement *args y **kwargs dans le code ?

13 votes

Une fois que vous les maîtriserez, vous ne voudrez plus jamais vous en passer (surtout si vous avez déjà eu à faire face à l'erreur de PHP). func_*_args() ).

5 votes

Les documents sont disponibles à l'adresse suivante docs.python.org/faq/programming.html#id13 au fait.

3 votes

En fait, ces deux formats d'arguments peuvent être ajoutés à n'importe quelle déclaration de fonction, à condition qu'ils soient les deux derniers. Notez l'ordre : explicit args, then *args, then **kwargs . par exemple def foo (arg1, arg2, *args, **kwargs): ...

1778voto

Dave Webb Points 90034

La syntaxe est la suivante * y ** . Les noms *args y **kwargs ne le sont que par convention, mais il n'y a aucune obligation de les utiliser.

Vous utiliseriez *args lorsque vous n'êtes pas sûr du nombre d'arguments qui peuvent être passés à votre fonction, c'est-à-dire qu'elle vous permet de passer un nombre arbitraire d'arguments à votre fonction. Par exemple :

>>> def print_everything(*args):
        for count, thing in enumerate(args):
...         print( '{0}. {1}'.format(count, thing))
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage

De même, **kwargs vous permet de gérer des arguments nommés que vous n'avez pas définis à l'avance :

>>> def table_things(**kwargs):
...     for name, value in kwargs.items():
...         print( '{0} = {1}'.format(name, value))
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit

Vous pouvez également les utiliser avec les arguments nommés. Les arguments explicites obtiennent des valeurs en premier et ensuite tout le reste est passé à *args y **kwargs . Les arguments nommés viennent en premier dans la liste. Par exemple :

def table_things(titlestring, **kwargs)

Vous pouvez également utiliser les deux dans la même définition de fonction mais *args doit se produire avant **kwargs .

Vous pouvez également utiliser le * y ** lors de l'appel d'une fonction. Par exemple :

>>> def print_three_things(a, b, c):
...     print( 'a = {0}, b = {1}, c = {2}'.format(a,b,c))
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> print_three_things(*mylist)
a = aardvark, b = baboon, c = cat

Comme vous pouvez le voir dans ce cas, il prend la liste (ou le tuple) d'éléments et la décompose. Ainsi, il les fait correspondre aux arguments de la fonction. Bien sûr, vous pourriez avoir un * à la fois dans la définition de la fonction et dans l'appel de la fonction.

15 votes

Comment trouver cette information dans l'aide/documentation de python ?

16 votes

@Alex : Ici

1 votes

Il semble impossible de développer une liste passée comme argument positionnel au milieu d'un appel de fonction comme dans function_call(arg1,arg2,*expanded_list_args,arg4,arg5) . La liste étendue ne peut être suivie que d'arguments de type mot-clé, je crois. Existe-t-il un moyen de contourner cela ?

512voto

Mark van Lent Points 3752

Un endroit où l'utilisation de *args y **kwargs est très utile pour la sous-classification.

class Foo(object):
    def __init__(self, value1, value2):
        # do something with the values
        print value1, value2

class MyFoo(Foo):
    def __init__(self, *args, **kwargs):
        # do something else, don't care about the args
        print 'myfoo'
        super(MyFoo, self).__init__(*args, **kwargs)

De cette façon, vous pouvez étendre le comportement de la classe Foo, sans avoir à en savoir trop sur Foo. Cela peut être très pratique si vous programmez pour une API qui pourrait changer. MyFoo passe simplement tous les arguments à la classe Foo.

141 votes

Cette réponse n'a vraiment de sens que si vous comprenez déjà * et **.

7 votes

Je ne comprends pas. Si votre API change, vous devez quand même changer tous les endroits où vous instanciez les classes enfant. Et si vous changez tous ces endroits, alors vous pourriez aussi bien faire en sorte que la signature de la classe enfant soit fixe, au lieu d'être bidouillée avec des args et des kwargs sans raison. Votre raisonnement sur le fait que cela ne nécessite pas la connaissance de Foo n'a pas de sens, parce que dès que la signature du constructeur de Foo change, tous vos appels d'instanciation de MyFoo devront changer aussi. Cela nécessite la connaissance de Foo et des paramètres que son constructeur requiert.

2 votes

@ZoranPavlovic Un exemple où cela pourrait être utilisé est dans une situation où vous fournissez un add-on pour un produit existant et souhaitez remplacer/étendre certaines fonctionnalités. En utilisant *args et **kwargs, ce module complémentaire continuera à fonctionner si le produit sous-jacent change. Cependant, l'instanciation de MyFoo se fait en dehors du module complémentaire. Est-ce que cela a (plus) de sens ? (Ceci dit : un décorateur est un meilleur exemple de quand on peut utiliser *args et **kwargs).

340voto

Kit Points 3864

Voici un exemple qui utilise 3 types de paramètres différents.

def func(required_arg, *args, **kwargs):
    # required_arg is a positional-only parameter.
    print required_arg

    # args is a tuple of positional arguments,
    # because the parameter name has * prepended.
    if args: # If args is not empty.
        print args

    # kwargs is a dictionary of keyword arguments,
    # because the parameter name has ** prepended.
    if kwargs: # If kwargs is not empty.
        print kwargs

>>> func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() takes at least 1 argument (0 given)

>>> func("required argument")
required argument

>>> func("required argument", 1, 2, '3')
required argument
(1, 2, '3')

>>> func("required argument", 1, 2, '3', keyword1=4, keyword2="foo")
required argument
(1, 2, '3')
{'keyword2': 'foo', 'keyword1': 4}

76voto

Wayne Werner Points 10172

Voici l'un de mes endroits préférés pour utiliser les ** syntaxe comme dans le dernier exemple de Dave Webb :

mynum = 1000
mystr = 'Hello World!'
print("{mystr} New-style formatting is {mynum}x more fun!".format(**locals()))

Je ne sais pas si c'est terriblement rapide par rapport à l'utilisation des noms eux-mêmes, mais c'est beaucoup plus facile à taper !

38 votes

Ce type a inventé les chaînes f de Python 3.6 avant que ce soit cool.

0 votes

@cat veuillez expliquer à quoi faites-vous référence exactement ? le format existe déjà même dans Python 2 ?

1 votes

@dabadaba f-strings, pas les chaînes de format (ex. f'{mystr} New-style formatting is {mynum}x more fun!' )

49voto

jchl Points 2538

Un cas où *args et **kwargs sont utiles est celui de l'écriture de fonctions enveloppes (comme les décorateurs) qui doivent pouvoir accepter des arguments arbitraires à transmettre à la fonction enveloppée. Par exemple, un décorateur simple qui imprime les arguments et la valeur de retour de la fonction enveloppée :

def mydecorator( f ):
   @functools.wraps( f )
   def wrapper( *args, **kwargs ):
      print "Calling f", args, kwargs
      v = f( *args, **kwargs )
      print "f returned", v
      return v
   return wrapper

0 votes

Pourquoi avons-nous besoin d'autres args et kwargs dans ce cas ? L'utilisation d'un seul des deux n'aurait pas le même effet ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X