Question * args et ** kwargs? [dupliquer]


Cette question a déjà une réponse ici:

J'ai donc du mal avec le concept de *args et **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 séparés et les valeurs deviennent des valeurs de ces arguments.

Je ne comprends pas à quelle tâche de programmation cela serait utile.

Peut être:

Je pense à entrer des listes et des dictionnaires comme arguments d'une fonction ET en même temps comme un joker, donc je peux passer n'importe quel argument?

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

Aussi le tutoriel que j'ai trouvé utilisé juste le "*" et un nom de variable.

Sont *args et **kwargs juste des espaces réservés ou utilisez-vous exactement *args et **kwargs dans le code?


1189
2017-08-03 08:28


origine


Réponses:


La syntaxe est la * et **. Les noms *args et **kwargs ne sont que par convention, mais il n'y a aucune exigence stricte pour les utiliser.

Vous utiliseriez *args lorsque vous n'êtes pas sûr du nombre d'arguments pouvant être transmis à votre fonction, c'est-à-dire qu'il vous permet de transmettre 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 les 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 des arguments nommés. Les arguments explicites obtiennent les valeurs en premier, puis tout le reste est passé à *args et **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 * et ** syntaxe 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 le décompresse. Par cela, il les associe 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.


1472
2017-08-03 08:38



Un endroit où l'utilisation de *args et **kwargs est très utile pour le sous-classement.

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 une API qui pourrait changer. MyFoo passe juste tous les arguments à la classe Foo.


442
2017-08-03 08:39



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}

278
2017-08-03 08:42



Voici l'un de mes endroits préférés pour utiliser le ** syntaxe comme dans l'exemple final 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 très rapide comparé à l'utilisation des noms eux-mêmes, mais c'est beaucoup plus facile à taper!


65
2017-08-03 13:03



Un cas où * args et ** kwargs sont utiles est lors de l'écriture de fonctions wrapper (comme les décorateurs) qui doivent pouvoir accepter des arguments arbitraires pour passer à la fonction en train d'être encapsulée. Par exemple, un simple décorateur qui imprime les arguments et renvoie la valeur de la fonction en cours d'encapsulation:

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

39
2017-08-03 08:40



* args et ** kwargs sont des fonctionnalités spéciales de Python. Pensez à une fonction qui pourrait avoir un nombre inconnu d'arguments. Par exemple, pour une raison quelconque, vous voulez avoir une fonction qui somme un nombre de nombres inconnu (et vous ne voulez pas utiliser la fonction de somme intégrée). Donc vous écrivez cette fonction:

def sumFunction(*args):
  result = 0
  for x in args:
    result += x
  return result

et l'utilise comme: sumFunction (3,4,6,3,6,8,9).

** kwargs a une fonction différente. Avec ** kwargs vous pouvez donner des arguments arbitraires à une fonction et vous pouvez y accéder en tant que dicton.

def someFunction(**kwargs):
  if 'text' in kwargs:
    print kwargs['text']

Appeler someFunction (text = "foo") imprimera foo.


35
2017-08-03 08:40



Imaginez que vous avez une fonction mais que vous ne voulez pas limiter le nombre de paramètres nécessaires. Exemple:

>>> import operator
>>> def multiply(*args):
...  return reduce(operator.mul, args)

Ensuite, vous utilisez cette fonction comme:

>>> multiply(1,2,3)
6

or

>>> numbers = [1,2,3]
>>> multiply(*numbers)
6

17
2017-08-03 08:40



Les noms *args et **kwargs ou **kw sont purement conventionnelles. Cela nous facilite la lecture du code de l'autre

Un endroit où il est pratique est d'utiliser le module struct

struct.unpack() retourne un tuple alors que struct.pack() utilise un nombre variable d'arguments. Lors de la manipulation des données, il est pratique de pouvoir passer un tuple à struck.pack() par exemple.

tuple_of_data = struct.unpack(format_str, data)
... manipulate the data
new_data = struct.pack(format_str, *tuple_of_data)

sans cette capacité, vous seriez obligé d'écrire

new_data = struct.pack(format_str, tuple_of_data[0], tuple_of_data[1], tuple_of_data[2],...)

ce qui signifie aussi que si le format_str change et que la taille du tuple change, je vais devoir revenir en arrière et modifier cette ligne vraiment longue


14
2017-08-03 08:32



Notez que * args / ** kwargs fait partie de la syntaxe d'appel de fonction, et pas vraiment un opérateur. Cela a un effet secondaire particulier que j'ai rencontré, à savoir que vous ne pouvez pas utiliser l'extension * args avec l'instruction print, car print n'est pas une fonction.

Cela semble raisonnable:

def myprint(*args):
    print *args

Malheureusement, il ne compile pas (erreur de syntaxe).

Cela compile:

def myprint(*args):
    print args

Mais imprime les arguments en tant que tuple, ce qui n'est pas ce que nous voulons.

C'est la solution sur laquelle je me suis arrêté:

def myprint(*args):
    for arg in args:
        print arg,
    print

9
2017-11-10 21:07



Ces paramètres sont généralement utilisés pour les fonctions proxy, de sorte que le proxy peut transmettre n'importe quel paramètre d'entrée à la fonction cible.

def foo(bar=2, baz=5):
    print bar, baz

def proxy(x, *args, **kwargs): # reqire parameter x and accept any number of additional arguments
    print x
    foo(*args, **kwargs) # applies the "non-x" parameter to foo

proxy(23, 5, baz='foo') # calls foo with bar=5 and baz=foo
proxy(6)# calls foo with its default arguments
proxy(7, bar='asdas') # calls foo with bar='asdas' and leave baz default argument

Mais puisque ces paramètres cachent les noms de paramètres réels, il est préférable de les éviter.


7
2017-08-03 08:41