Quel est le but et l'utilisation de ** kwargs?

763

À quoi servent **kwargsen Python?

Je sais que vous pouvez faire un objects.filtersur une table et passer un **kwargsargument.  

Puis-je également le faire pour spécifier les deltas de temps, c'est timedelta(hours = time1)-à- dire ?

Comment ça marche exactement? Est-ce que les classes sont «déballées»? Comme a,b=1,2?

Federer
la source
27
Si vous rencontrez cette question comme moi, voyez aussi: * args et ** kwargs?
somptueux
3
Une explication remarquablement concise ici : "* recueille tous les arguments de position dans un tuple", "** recueille tous les arguments de mot-clé dans un dictionnaire". Le mot clé est recueille .
osa
24
Just FYI: kwargssignifie KeyWord ARGumentS, c'est-à-dire des arguments qui ont défini des clés
Richard de Wit

Réponses:

868

Vous pouvez utiliser **kwargspour laisser vos fonctions prendre un nombre arbitraire d'arguments de mot-clé ("kwargs" signifie "arguments de mot-clé"):

>>> def print_keyword_args(**kwargs):
...     # kwargs is a dict of the keyword args passed to the function
...     for key, value in kwargs.iteritems():
...         print "%s = %s" % (key, value)
... 
>>> print_keyword_args(first_name="John", last_name="Doe")
first_name = John
last_name = Doe

Vous pouvez également utiliser le **kwargs syntaxe lors de l'appel de fonctions en construisant un dictionnaire d'arguments de mots clés et en le transmettant à votre fonction:

>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith

le didacticiel Python contient une bonne explication de son fonctionnement, ainsi que de beaux exemples.

<--Mise à jour-->

Pour les personnes utilisant Python 3, au lieu de iteritems (), utilisez items ()

Pär Wieslander
la source
1
@ yashas123 Non; si vous bouclez sur quelque chose de vide, rien ne se passe, donc le code qui vient ensuite s'exécute normalement.
JG
330

Déballage des dictionnaires

** décompresse les dictionnaires.

Cette

func(a=1, b=2, c=3)

est le même que

args = {'a': 1, 'b': 2, 'c':3}
func(**args)

C'est utile si vous devez construire des paramètres:

args = {'name': person.name}
if hasattr(person, "address"):
    args["address"] = person.address
func(**args)  # either expanded to func(name=person.name) or
              #                    func(name=person.name, address=person.address)

Paramètres d'emballage d'une fonction

def setstyle(**styles):
    for key, value in styles.iteritems():      # styles is a regular dictionary
        setattr(someobject, key, value)

Cela vous permet d'utiliser la fonction comme ceci:

setstyle(color="red", bold=False)
Georg Schölly
la source
13
est kwarg est juste un nom de variable à droite? donc je peux utiliser def func (** args): et ça marche?
Sriram
11
@Sriram: D'accord. Les astérisques sont importants. kwargs n'est que le nom qu'on lui donne s'il n'y a pas mieux. (Habituellement, il y en a.)
Georg Schölly
54
@Sriram: pour des raisons de lisibilité, vous devriez vous en tenir aux kwargs - les autres programmeurs l'apprécieront.
johndodo
12
** do unpack dictionaries.>> époustouflant / bien sûr! +1 pour expliquer ce bit.
Marc
13
Remarque: .iteritems()a été renommé .items()en Python 3.
fnkr
67

kwargs est juste un dictionnaire qui est ajouté aux paramètres.

Un dictionnaire peut contenir des paires clé / valeur. Et ce sont les kwargs. Ok, c'est comme ça.

Le pourquoi n'est pas si simple.

Par exemple (très hypothétique), vous avez une interface qui appelle simplement d'autres routines pour faire le travail:

def myDo(what, where, why):
   if what == 'swim':
      doSwim(where, why)
   elif what == 'walk':
      doWalk(where, why)
   ...

Vous obtenez maintenant une nouvelle méthode "drive":

elif what == 'drive':
   doDrive(where, why, vehicle)

Mais attendez une minute, il y a un nouveau paramètre "véhicule" - vous ne le saviez pas auparavant. Vous devez maintenant l'ajouter à la signature de la fonction myDo.

Ici, vous pouvez lancer des kwargs en jeu - vous ajoutez simplement des kwargs à la signature:

def myDo(what, where, why, **kwargs):
   if what == 'drive':
      doDrive(where, why, **kwargs)
   elif what == 'swim':
      doSwim(where, why, **kwargs)

De cette façon, vous n'avez pas besoin de changer la signature de votre fonction d'interface à chaque fois que certaines de vos routines appelées peuvent changer.

Ceci est juste un bel exemple que vous pourriez trouver utile pour kwargs.

Juergen
la source
46

Partant du principe qu'un bon échantillon est parfois meilleur qu'un long discours, j'écrirai deux fonctions en utilisant toutes les facilités de passage d'arguments variables python (à la fois des arguments positionnels et nommés). Vous devriez facilement pouvoir voir ce qu'il fait par vous-même:

def f(a = 0, *args, **kwargs):
    print("Received by f(a, *args, **kwargs)")
    print("=> f(a=%s, args=%s, kwargs=%s" % (a, args, kwargs))
    print("Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)")
    g(10, 11, 12, *args, d = 13, e = 14, **kwargs)

def g(f, g = 0, *args, **kwargs):
    print("Received by g(f, g = 0, *args, **kwargs)")
    print("=> g(f=%s, g=%s, args=%s, kwargs=%s)" % (f, g, args, kwargs))

print("Calling f(1, 2, 3, 4, b = 5, c = 6)")
f(1, 2, 3, 4, b = 5, c = 6)

Et voici la sortie:

Calling f(1, 2, 3, 4, b = 5, c = 6)
Received by f(a, *args, **kwargs) 
=> f(a=1, args=(2, 3, 4), kwargs={'c': 6, 'b': 5}
Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)
Received by g(f, g = 0, *args, **kwargs)
=> g(f=10, g=11, args=(12, 2, 3, 4), kwargs={'c': 6, 'b': 5, 'e': 14, 'd': 13})
kriss
la source
28

Motif: *argset **kwargssert d'espace réservé pour les arguments qui doivent être passés à un appel de fonction

en utilisant *argset **kwargspour appeler une fonction

def args_kwargs_test(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

Nous allons maintenant utiliser *argspour appeler la fonction définie ci-dessus

#args can either be a "list" or "tuple"
>>> args = ("two", 3, 5)  
>>> args_kwargs_test(*args)

résultat:

arg1: deux
arg2: 3
arg3: 5


Maintenant, utiliser **kwargspour appeler la même fonction

#keyword argument "kwargs" has to be a dictionary
>>> kwargs = {"arg3":3, "arg2":'two', "arg1":5}
>>> args_kwargs_test(**kwargs)

résultat:

arg1: 5
arg2: deux
arg3: 3

Bottomline: *argsn'a aucune intelligence, il interpole simplement les arguments passés aux paramètres (de gauche à droite) tout en **kwargsse comportant intelligemment en plaçant la valeur appropriée @ l'endroit requis

kmario23
la source
24
  • kwargsdans **kwargsest juste un nom de variable. Vous pouvez très bien avoir**anyVariableName
  • kwargssignifie "arguments de mots clés". Mais je pense qu'ils devraient être mieux appelés comme "arguments nommés", car ce sont simplement des arguments transmis avec des noms (je ne trouve aucune signification au mot "mot-clé" dans le terme "arguments de mot-clé". Je suppose que "mot-clé" signifie généralement mots réservés par le langage de programmation et donc ne pas être utilisés par le programmeur pour les noms de variables. Rien de tel ne se passe ici en cas de kwargs.). Donc , nous donnons des noms param1et param2à deux valeurs de paramètres transmis à la fonction comme suit: func(param1="val1",param2="val2"), au lieu de passer uniquement les valeurs: func(val1,val2). Ainsi, je pense qu'ils devraient être appelés de façon appropriée "nombre arbitraire d'arguments nommés" car nous pouvons spécifier n'importe quel nombre de ces paramètres (c'est-à-dire,funcfunc(**kwargs)

Cela étant dit, permettez-moi d'abord d'expliquer les "arguments nommés", puis "le nombre arbitraire d'arguments nommés" kwargs.

Arguments nommés

  • les arguments nommés doivent suivre les arguments positionnels
  • l'ordre des arguments nommés n'est pas important
  • Exemple

    def function1(param1,param2="arg2",param3="arg3"):
        print("\n"+str(param1)+" "+str(param2)+" "+str(param3)+"\n")
    
    function1(1)                      #1 arg2 arg3   #1 positional arg
    function1(param1=1)               #1 arg2 arg3   #1 named arg
    function1(1,param2=2)             #1 2 arg3      #1 positional arg, 1 named arg
    function1(param1=1,param2=2)      #1 2 arg3      #2 named args       
    function1(param2=2, param1=1)     #1 2 arg3      #2 named args out of order
    function1(1, param3=3, param2=2)  #1 2 3         #
    
    #function1()                      #invalid: required argument missing
    #function1(param2=2,1)            #invalid: SyntaxError: non-keyword arg after keyword arg
    #function1(1,param1=11)           #invalid: TypeError: function1() got multiple values for argument 'param1'
    #function1(param4=4)              #invalid: TypeError: function1() got an unexpected keyword argument 'param4'

Nombre arbitraire d'arguments nommés kwargs

  • Séquence des paramètres de fonction:
    1. paramètres de position
    2. paramètre formel capturant un nombre arbitraire d'arguments (préfixé par *)
    3. paramètres formels nommés
    4. paramètre formel capturant un nombre arbitraire de paramètres nommés (préfixé par **)
  • Exemple

    def function2(param1, *tupleParams, param2, param3, **dictionaryParams):
        print("param1: "+ param1)
        print("param2: "+ param2)
        print("param3: "+ param3)
        print("custom tuple params","-"*10)
        for p in tupleParams:
            print(str(p) + ",")
        print("custom named params","-"*10)
        for k,v in dictionaryParams.items():
            print(str(k)+":"+str(v))
    
    function2("arg1",
              "custom param1",
              "custom param2",
              "custom param3",
              param3="arg3",
              param2="arg2", 
              customNamedParam1 = "val1",
              customNamedParam2 = "val2"
              )
    
    # Output
    #
    #param1: arg1
    #param2: arg2
    #param3: arg3
    #custom tuple params ----------
    #custom param1,
    #custom param2,
    #custom param3,
    #custom named params ----------
    #customNamedParam2:val2
    #customNamedParam1:val1

Passer des variables tuple et dict pour les arguments personnalisés

Pour terminer, permettez-moi également de noter que nous pouvons passer

  • "paramètre formel capturant un nombre arbitraire d'arguments" comme variable de tuple et
  • "paramètre formel capturant un nombre arbitraire de paramètres nommés" comme variable dict

Ainsi, le même appel ci-dessus peut être effectué comme suit:

tupleCustomArgs = ("custom param1", "custom param2", "custom param3")
dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"}

function2("arg1",
      *tupleCustomArgs,    #note *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs     #note **
      )

Enfin, notez *et **dans les appels de fonction ci-dessus. Si nous les omettons, nous pourrions obtenir de mauvais résultats.

Omettre *dans les arguments de tuple:

function2("arg1",
      tupleCustomArgs,   #omitting *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs
      )

impressions

param1: arg1
param2: arg2
param3: arg3
custom tuple params ----------
('custom param1', 'custom param2', 'custom param3'),
custom named params ----------
customNamedParam2:val2
customNamedParam1:val1

Le tuple ci-dessus ('custom param1', 'custom param2', 'custom param3')est imprimé tel quel.

Omettre les dictarguments:

function2("arg1",
      *tupleCustomArgs,   
      param3="arg3",
      param2="arg2", 
      dictCustomNamedArgs   #omitting **
      )

donne

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg
Mahesha999
la source
3
J'imagine que la keywordterminologie vient du fait que vous passez dans un dict qui est une base de données de paires clé-valeur.
crobar
voulez-vous dire le mot «clé» dans les paires «clé» -valeur? De plus, ce n'est généralement pas appelé base de données, mais dictionnaire. Mais toujours pas en mesure de trouver une signification à l'utilisation du mot "mot-clé".
Mahesha999
9

En complément, vous pouvez également mélanger différentes manières d'utilisation lors de l'appel des fonctions kwargs:

def test(**kwargs):
    print kwargs['a']
    print kwargs['b']
    print kwargs['c']


args = { 'b': 2, 'c': 3}

test( a=1, **args )

donne cette sortie:

1
2
3

Notez que ** kwargs doit être le dernier argument

philipp
la source
5

kwargs est un sucre syntaxique pour passer des arguments de nom en tant que dictionnaires (pour func), ou des dictionnaires en tant qu'arguments nommés (pour func)


la source
5

Voici une fonction simple qui sert à expliquer l'utilisation:

def print_wrap(arg1, *args, **kwargs):
    print(arg1)
    print(args)
    print(kwargs)
    print(arg1, *args, **kwargs)

Tous les arguments qui ne sont pas spécifiés dans la définition de la fonction seront placés dans la argsliste ou la kwargsliste, selon qu'il s'agit d'arguments de mots clés ou non:

>>> print_wrap('one', 'two', 'three', end='blah', sep='--')
one
('two', 'three')
{'end': 'blah', 'sep': '--'}
one--two--threeblah

Si vous ajoutez un argument de mot clé qui n'est jamais transmis à une fonction, une erreur sera générée:

>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function
rien101
la source
1

Voici un exemple que j'espère utile:

#! /usr/bin/env python
#
def g( **kwargs) :
  print ( "In g ready to print kwargs" )
  print kwargs
  print ( "in g, calling f")
  f ( **kwargs )
  print ( "In g, after returning from f")

def f( **kwargs ) :
  print ( "in f, printing kwargs")
  print ( kwargs )
  print ( "In f, after printing kwargs")


g( a="red", b=5, c="Nassau")

g( q="purple", w="W", c="Charlie", d=[4, 3, 6] )

Lorsque vous exécutez le programme, vous obtenez:

$ python kwargs_demo.py 
In g ready to print kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
in g, calling f
in f, printing kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
In f, after printing kwargs
In g, after returning from f
In g ready to print kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
in g, calling f
in f, printing kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
In f, after printing kwargs
In g, after returning from f

La clé à retenir ici est que le nombre variable d'arguments nommés dans l'appel se traduit par un dictionnaire dans la fonction.

user1928764
la source
0

Ceci est l'exemple simple à comprendre sur le déballage de python ,

>>> def f(*args, **kwargs):
...    print 'args', args, 'kwargs', kwargs

eg1:

>>>f(1, 2)
>>> args (1,2) kwargs {} #args return parameter without reference as a tuple
>>>f(a = 1, b = 2)
>>> args () kwargs {'a': 1, 'b': 2} #args is empty tuple and kwargs return parameter with reference as a dictionary
Mohideen bin Mohammed
la source
0

En Java, vous utilisez des constructeurs pour surcharger les classes et autoriser plusieurs paramètres d'entrée. En python, vous pouvez utiliser kwargs pour fournir un comportement similaire.

exemple java: https://beginnersbook.com/2013/05/constructor-overloading/

exemple de python:

class Robot():
    # name is an arg and color is a kwarg
    def __init__(self,name, color='red'):
        self.name = name
        self.color = color

red_robot = Robot('Bob')
blue_robot = Robot('Bob', color='blue')

print("I am a {color} robot named {name}.".format(color=red_robot.color, name=red_robot.name))
print("I am a {color} robot named {name}.".format(color=blue_robot.color, name=blue_robot.name))

>>> I am a red robot named Bob.
>>> I am a blue robot named Bob.

juste une autre façon d'y penser.

Aidan Melen
la source
0

Les arguments de mots clés sont souvent raccourcis en kwargs en Python. En programmation informatique ,

Les arguments de mots clés font référence à la prise en charge par un langage informatique des appels de fonction qui indiquent clairement le nom de chaque paramètre dans l'appel de fonction.

L'utilisation des deux astérisques avant le nom du paramètre, ** kwargs , est quand on ne sait pas combien d'arguments de mot-clé seront passés dans la fonction. Dans ce cas, cela s'appelle Arguments de mots-clés arbitraires / génériques.

Un exemple de ceci est les fonctions de récepteur de Django .

def my_callback(sender, **kwargs):
    print("Request finished!")

Notez que la fonction prend un argument expéditeur, ainsi que des arguments de mots clés génériques (** kwargs); tous les gestionnaires de signaux doivent prendre ces arguments. Tous les signaux envoient des arguments de mots clés et peuvent modifier ces arguments de mots clés à tout moment. Dans le cas de request_finished , il est documenté comme n'envoyant aucun argument, ce qui signifie que nous pourrions être tentés d'écrire notre gestion du signal comme my_callback (sender).

Ce serait faux - en fait, Django lancera une erreur si vous le faites. En effet, à tout moment, des arguments pourraient être ajoutés au signal et votre récepteur doit être capable de gérer ces nouveaux arguments.

Notez qu'il ne doit pas être appelé kwargs , mais il doit avoir ** (le nom kwargs est une convention).

Tiago Martins Peres 李大仁
la source