web-dev-qa-db-fra.com

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

Quelles sont les utilisations de **kwargs en Python?

Je sais que vous pouvez faire un objects.filter sur une table et passer un argument **kwargs.

Puis-je également le faire pour spécifier des deltas de temps, à savoir timedelta(hours = time1)?

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

736
Federer

Vous pouvez utiliser **kwargs pour permettre à vos fonctions de prendre un nombre arbitraire d'arguments de mots clés ("kwargs" signifie "arguments de mots clés"):

>>> 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 la syntaxe **kwargs lors de l'appel de fonctions en créant 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 Tutoriel Python contient une bonne explication de son fonctionnement, ainsi que quelques exemples intéressants.

<- Mise à jour ->

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

837
Pär Wieslander

Déballer 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)
315
Georg Schölly

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 quoi pour 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)
   ...

Maintenant, vous obtenez 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 avant. Maintenant, vous devez l'ajouter à la signature de la fonction myDo.

Ici, vous pouvez lancer kwargs - vous ajoutez simplement 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.

Ce n'est qu'un bel exemple que vous pourriez trouver utile.

63
Juergen

Sur la base du fait qu'un bon échantillon vaut parfois mieux qu'un long discours, j'écrirai deux fonctions en utilisant toutes les facilités de transmission d'arguments variables python (arguments de position et nommés). Vous devriez pouvoir facilement voir ce que cela fait 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})
46
kriss

Motif: *args et **kwargs sert de paramètre fictif pour les arguments devant être passés à un appel de fonction

utiliser *args et **kwargs pour appeler une fonction

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

Nous allons maintenant utiliser *args pour 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, en utilisant **kwargs pour 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: *args n’a pas d’intelligence, il interpole simplement les arguments passés aux paramètres (dans l’ordre de gauche à droite) tandis que **kwargs se comporte de manière intelligente en plaçant la valeur appropriée à la place souhaitée.

27
kmario23
  • kwargs dans **kwargs n'est qu'un nom de variable. Vous pouvez très bien avoir **anyVariableName
  • kwargs signifie "arguments de mots clés". Mais j'estime qu'ils devraient être appelés "arguments nommés", car il s'agit simplement d'arguments transmis avec des noms (je ne trouve aucune signification pour le mot "mot clé" dans le terme "arguments mot clé". J'imagine que "mot clé" signifie généralement mots réservés par le langage de programmation et ne pouvant donc pas être utilisés par le programmeur pour les noms de variables, rien de tel ne se produit ici dans le cas de kwargs.). Nous attribuons donc les noms param1 et param2 à deux valeurs de paramètre transmises à la fonction comme suit: func(param1="val1",param2="val2"), au lieu de ne transmettre que les valeurs: func(val1,val2). Ainsi, j'estime qu'ils devraient être appelés de manière appropriée "nombre arbitraire d'arguments nommés" car nous pouvons spécifier un nombre quelconque de ces paramètres (c'est-à-dire des arguments) si func a la signature func(**kwargs)

Cela étant dit, laissez-moi d'abord expliquer les "arguments nommés", puis "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 de tuple et de dict pour des arguments personnalisés

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

  • "paramètre formel capturant un nombre arbitraire d'arguments" en tant que variable Tuple et
  • "paramètre formel capturant un nombre arbitraire de paramètres nommés" en tant que variable dict

Ainsi, le même appel ci-dessus peut être fait 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
      )

empreintes

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

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

Omettre dict args:

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

donne

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg
21
Mahesha999

De plus, vous pouvez également combiner différents modes d’utilisation lorsque vous appelez les fonctions de 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

9
philipp

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 spécifiés par pas dans la définition de la fonction seront placés dans la liste args ou dans la liste kwargs, selon qu’il s’agit ou non d’arguments mot-clé:

>>> 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
5
naught101

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.

1
user1928764

C’est un exemple simple à comprendre à propos de décompression 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
0