Question Comprendre kwargs en Python


Quelles sont les utilisations pour **kwargs en Python?

Je sais que tu peux faire un objects.filter sur une table et passer dans un **kwargs argument.

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

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


643
2017-11-20 09:40


origine


Réponses:


Vous pouvez utiliser **kwargs pour 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 et en le passant à 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 comment cela fonctionne, avec quelques bons exemples.

<- Mise à jour ->

Pour les utilisateurs de Python 3, au lieu de iteritems (), utilisez des items ()


729
2017-11-20 09:58



Déballer des dictionnaires

** décompresse les dictionnaires.

Ce

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)

278
2017-11-20 09:59



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

Un dictionnaire peut contenir des paires de clés et de valeurs. Et ce sont les kwargs. Ok, c'est comme ça.

Le whatfor 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. Vous devez maintenant l'ajouter à la signature de la fonction myDo.

Ici vous pouvez lancer kwargs - vous ajoutez juste 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 bon exemple que vous pourriez trouver utile kwargs.


57
2017-11-20 09:51



Étant donné 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 (les 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})

40
2018-01-24 16:56



Motif: *args et **kwargs sert d'espace réservé pour les arguments qui doivent être passés à un appel de fonction

en utilisant *args et **kwargs appeler une fonction

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

Maintenant, nous allons utiliser *args 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 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 aucune intelligence, il interpole simplement les args passés aux paramètres (de gauche à droite) tout en **kwargs se comporte intelligemment en plaçant la valeur appropriée @ l'endroit requis


21
2018-01-06 06:57



  • kwargs dans **kwargs est juste un nom de variable. Vous pouvez très bien avoir **anyVariableName
  • kwargs est synonyme de "mots-clés". Mais je pense qu'il vaut mieux les appeler "arguments nommés", car ce ne sont que des arguments passés avec des noms (je ne trouve aucune signification au mot "mot-clé" dans le terme "mots-clés". mots réservés par le langage de programmation et donc ne pas être utilisés par le programmeur pour les noms de variables, ce qui n'est pas le cas ici pour kwargs.). Nous donnons donc des noms param1 et param2à deux valeurs de paramètre passées à la fonction comme suit: func(param1="val1",param2="val2"), au lieu de transmettre uniquement des valeurs: func(val1,val2). Ainsi, je pense qu'ils devraient être appelés de façon appropriée "nombre arbitraire d'arguments nommés" comme nous pouvons spécifier un certain nombre de ces paramètres (c'est-à-arguments) si func a la signature func(**kwargs)

Donc étant dit que permettez-moi d'expliquer "arguments nommés" d'abord, 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 de paramètres de fonction:
    1. paramètres de position
    2. paramètre formel capturant un nombre arbitraire d'arguments (précédé de *)
    3. paramètres formels nommés
    4. paramètre formel capturant un nombre arbitraire de paramètres nommés (précédé de **)
  • 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 dic pour des arguments personnalisés

Pour finir, permettez-moi aussi de noter que nous pouvons passer

  • "paramètre formel capturant un nombre arbitraire d'arguments" comme variable tuple et
  • "paramètre formel capturant un nombre arbitraire de paramètres nommés" comme variable de 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 noter * et ** dans les appels de fonction ci-dessus. Si nous les omettons, nous pourrions avoir de mauvais résultats.

Omettre * en tuple args:

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

imprime

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

Au-dessus de 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

16
2017-09-20 07:19



En plus, vous pouvez aussi mélanger différentes façons d'utiliser 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
2018-02-25 09:45



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)


5
2017-11-20 10:39



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 sont ne pas spécifié dans la définition de la fonction sera mis dans le args liste, ou la kwargs liste, selon qu'ils sont des arguments de mot-clé ou non:

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

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

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

5
2017-11-27 06:15



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
2018-05-26 21:37