Qual è lo scopo e l'uso di ** kwargs?


763

A cosa servono **kwargsPython?

So che puoi fare qualcosa objects.filtersu un tavolo e passare una **kwargsdiscussione.  

Posso farlo anche per specificare i delta temporali, ad esempio timedelta(hours = time1)?

Come funziona esattamente? Si tratta di classi come 'disimballaggio'? Come a,b=1,2?


27
Se incontri questa domanda come me, vedi anche: * args e ** kwargs?
somma

3
Una spiegazione straordinariamente concisa qui : "* raccoglie tutti gli argomenti posizionali in una tupla", "** raccoglie tutti gli argomenti delle parole chiave in un dizionario". La parola chiave è raccoglie .
osa,

24
Cordiali saluti: kwargssta per KeyWord ARGumentS, vale a dire argomenti che hanno impostato le chiavi
Richard de Wit il

Risposte:


868

Puoi usare **kwargsper consentire alle tue funzioni di accettare un numero arbitrario di argomenti per parole chiave ("kwargs" significa "argomenti per parole chiave"):

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

È inoltre possibile utilizzare la **kwargssintassi quando si chiamano funzioni costruendo un dizionario di argomenti di parole chiave e passandolo alla propria funzione:

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

Il tutorial di Python contiene una buona spiegazione di come funziona, insieme ad alcuni begli esempi.

<- Aggiornamento ->

Per le persone che usano Python 3, invece di iteritems (), usa items ()


1
@ yashas123 No; se esegui il ciclo su qualcosa che è vuoto, non accade nulla, quindi qualunque codice potrebbe venire dopo viene eseguito normalmente.
JG

330

Disimballare i dizionari

** decomprime i dizionari.

Questo

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

equivale a

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

È utile se devi costruire parametri:

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)

Parametri di imballaggio di una funzione

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

Ciò consente di utilizzare la funzione in questo modo:

setstyle(color="red", bold=False)

13
è kwarg è solo un nome di variabile giusto? così posso usare def func (** args): e funzionerebbe?
Sriram,

11
@Siriram: giusto. Gli asterischi sono importanti. kwargs è solo il nome che gli viene dato se non c'è di meglio. (Di solito c'è.)
Georg Schölly,

54
@Sriram: per motivi di leggibilità dovresti attenersi a kwargs - altri programmatori lo apprezzeranno.
johndodo,

12
** do unpack dictionaries.>> strabiliato / ovviamente! +1 per spiegare quel bit.
Marc

13
Nota: .iteritems()è stato rinominato .items()in Python 3.
fnkr il

67

kwargs è solo un dizionario che viene aggiunto ai parametri.

Un dizionario può contenere chiavi, coppie di valori. E quelli sono i kwargs. Ok, ecco come.

Il per cosa non è così semplice.

Ad esempio (molto ipotetico) hai un'interfaccia che chiama semplicemente altre routine per fare il lavoro:

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

Ora ottieni un nuovo metodo "drive":

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

Ma aspetta un minuto, c'è un nuovo parametro "veicolo" - non lo sapevi prima. Ora è necessario aggiungerlo alla firma della funzione myDo.

Qui puoi mettere in gioco i kwarg - aggiungi semplicemente kwarg alla firma:

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

In questo modo non è necessario modificare la firma della funzione dell'interfaccia ogni volta che alcune delle routine chiamate potrebbero cambiare.

Questo è solo un bell'esempio che potresti trovare utile in kwargs.


46

Sulla base del fatto che a volte un buon campione è meglio di un lungo discorso, scriverò due funzioni usando tutte le variabili di Python che passano le strutture (sia argomenti posizionali che argomenti denominati). Dovresti essere in grado di vedere facilmente cosa fa da solo:

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)

Ed ecco l'output:

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})

28

Motivo: *argse **kwargsfunge da segnaposto per gli argomenti che devono essere passati a una chiamata di funzione

usando *argse **kwargsper chiamare una funzione

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

Ora useremo *argsper chiamare la funzione sopra definita

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

risultato:

arg1: two
arg2: 3
arg3: 5


Ora, usando **kwargsper chiamare la stessa funzione

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

risultato:

arg1: 5
arg2: due
arg3: 3

Bottomline: *argsnon ha intelligenza, interpola semplicemente gli argomenti passati ai parametri (nell'ordine da sinistra a destra) mentre **kwargssi comporta in modo intelligente posizionando il valore appropriato @ il posto richiesto


24
  • kwargsin **kwargsè solo il nome della variabile. Puoi benissimo averlo**anyVariableName
  • kwargssta per "argomenti di parole chiave". Ma credo che dovrebbero essere chiamati come "argomenti con nome", in quanto si tratta semplicemente di argomenti passati insieme ai nomi (non trovo alcun significato per la parola "parola chiave" nel termine "argomenti chiave". Immagino che "parola chiave" di solito significhi parole riservate dal linguaggio di programmazione e quindi non utilizzate dal programmatore per i nomi delle variabili. Qui non accade nulla di simile in caso di kwargs.). Così diamo nomi param1e param2ai due valori di parametro passati alla funzione come segue: func(param1="val1",param2="val2"), invece di passare solo valori: func(val1,val2). Pertanto, ritengo che dovrebbero essere opportunamente chiamati "numero arbitrario di argomenti denominati" in quanto possiamo specificare qualsiasi numero di questi parametri (ovverofuncfunc(**kwargs)

Detto questo, mi spiego prima "argomenti nominati" e poi "numero arbitrario di argomenti nominati" kwargs.

Argomenti nominati

  • args nominati dovrebbero seguire args posizionali
  • l'ordine dei nomi args non è importante
  • Esempio

    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'

Numero arbitrario di argomenti denominati kwargs

  • Sequenza di parametri funzionali:
    1. parametri posizionali
    2. parametro formale che acquisisce un numero arbitrario di argomenti (preceduto da *)
    3. parametri formali nominati
    4. parametro formale che acquisisce un numero arbitrario di parametri nominati (preceduto da **)
  • Esempio

    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

Passando variabili tuple e dict per argomenti personalizzati

Per finire, fammi anche notare che possiamo passare

  • "parametro formale che cattura un numero arbitrario di argomenti" come variabile tupla e
  • "parametro formale che acquisisce un numero arbitrario di parametri nominati" come variabile dict

Quindi la stessa chiamata sopra può essere effettuata come segue:

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

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

Infine nota *e **in chiamate di funzione sopra. Se li omettiamo, potremmo ottenere risultati negativi.

Omettere *in tuple args:

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

stampe

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

Sopra la tupla ('custom param1', 'custom param2', 'custom param3')è stampata così com'è.

Omettere dictargs:

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

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg

3
Immagino che la keywordterminologia derivi dal fatto che stai passando un dict che è un database di coppie chiave-valore.
crobar,

intendi la parola "chiave" nelle coppie di valori "chiave"? Inoltre, di solito non è chiamato database, ma dizionario. Ma non riesco ancora a trovare alcun significato per l'uso della parola "parola chiave".
Mahesha999,

9

Inoltre, puoi anche mescolare diversi modi di utilizzo quando chiami le funzioni di kwargs:

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


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

test( a=1, **args )

dà questo risultato:

1
2
3

Nota che ** kwargs deve essere l'ultimo argomento


5

i kwargs sono uno zucchero sintattico per passare argomenti di nomi come dizionari (per func) o dizionari come argomenti denominati (per func)


5

Ecco una semplice funzione che serve a spiegare l'uso:

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

Qualsiasi argomento non specificato nella definizione della funzione verrà inserito argsnell'elenco o kwargsnell'elenco, a seconda che si tratti o meno di argomenti di parole chiave:

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

Se aggiungi un argomento di parole chiave che non viene mai passato a una funzione, verrà generato un errore:

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

1

Ecco un esempio che spero sia 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] )

Quando esegui il programma, ottieni:

$ 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 chiave da asporto è che il numero variabile di argomenti denominati nella chiamata viene tradotto in un dizionario nella funzione.


0

Questo è il semplice esempio per comprendere il disimballaggio di 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

In Java, si utilizzano costruttori per sovraccaricare le classi e consentire più parametri di input. In Python, puoi usare kwargs per fornire un comportamento simile.

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

esempio di 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.

solo un altro modo di pensarci.


0

Gli argomenti delle parole chiave sono spesso abbreviati in kwargs in Python. Nella programmazione informatica ,

gli argomenti di parole chiave si riferiscono al supporto di un linguaggio informatico per le chiamate di funzione che indicano chiaramente il nome di ciascun parametro all'interno della chiamata di funzione.

L'utilizzo dei due asterisco prima del nome del parametro, ** kwargs , è quando non si sa quanti argomenti di parole chiave verranno passati nella funzione. In questo caso, si chiama Arbitrary / Wildcard Keyword Argomenti.

Un esempio di ciò sono le funzioni del ricevitore di Django .

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

Si noti che la funzione accetta un argomento mittente, insieme a argomenti con parole chiave jolly (** kwargs); tutti i gestori di segnali devono accettare questi argomenti. Tutti i segnali inviano argomenti per parole chiave e possono modificare tali argomenti in qualsiasi momento. Nel caso di request_finished , è documentato come l'invio di nessun argomento, il che significa che potremmo essere tentati di scrivere la nostra gestione del segnale come my_callback (mittente).

Questo sarebbe sbagliato - in effetti, Django genererà un errore se lo fai. Questo perché in qualsiasi momento è possibile aggiungere argomenti al segnale e il ricevitore deve essere in grado di gestire questi nuovi argomenti.

Nota che non deve essere chiamato kwargs , ma deve avere ** (il nome kwargs è una convenzione).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.