number - python3 variable arguments




Capire kwargs in Python (7)

Quali sono gli usi per **kwargs in Python?

So che puoi fare un objects.filter su un tavolo e passare un argomento **kwargs .

Posso fare anche questo per specificare i delta timedelta(hours = time1) time ie timedelta(hours = time1) ?

Come funziona esattamente? Classi come 'disimballaggio'? Come a,b=1,2 ?


Disimballaggio dei 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)

Questo ti permette di usare la funzione in questo modo:

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

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 prendere qui è che il numero variabile di argomenti nominati nella chiamata si traduce in un dizionario nella funzione.


In aggiunta, 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


Puoi utilizzare **kwargs per consentire alle tue funzioni di assumere un numero arbitrario di argomenti per le parole chiave ("kwargs" significa "argomenti per le 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

Puoi anche utilizzare la sintassi **kwargs quando chiamate le funzioni costruendo un dizionario di argomenti per parole chiave e passandoli alla tua funzione:

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

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

<- Aggiornamento ->

Per chi usa Python 3, invece di iteritems (), usa items ()


i kwarg sono uno zucchero sintattico per passare argomenti di nome come dizionari (per func), o dizionari come argomenti con nome (per func)


kwargs è solo un dizionario che viene aggiunto ai parametri.

Un dizionario può contenere coppie chiave, valore. E questi sono i kwarg. Ok, questo è il modo.

Il whatfor non è così semplice.

Ad esempio (molto ipotetico) hai un'interfaccia che chiama solo 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 "guida":

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

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

Qui puoi lanciare i kwarg in gioco - aggiungi solo kwargs 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 di interfaccia ogni volta che alcune delle routine chiamate potrebbero cambiare.

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


  • kwargs in **kwargs è solo nome variabile. Puoi benissimo avere **anyVariableName
  • kwargs sta per "argomenti per parole chiave". Ma penso che dovrebbero essere meglio definiti come "argomenti nominati", in quanto questi sono semplicemente argomenti passati insieme a nomi (non trovo alcun significato per la parola "parola chiave" nel termine "argomenti di parole chiave". parole riservate dal linguaggio di programmazione e quindi non usate dal programmatore per i nomi delle variabili. Non succede nulla di simile qui in caso di kwargs.). Quindi diamo nomi param1 e param2 a due valori di parametro passati alla funzione come segue: func(param1="val1",param2="val2") , invece di passare solo valori: func(val1,val2) . Quindi, ritengo che dovrebbero essere chiamati appropriatamente "numero arbitrario di argomenti nominati" poiché possiamo specificare qualsiasi numero di questi parametri (cioè argomenti) se func ha signature func(**kwargs)

Detto questo, lasciatemi spiegare prima "argomenti con nome" e poi "numero arbitrario di argomenti con nome" kwargs .

Argomenti nominati

  • args nominati dovrebbero seguire argomenti posizionali
  • l'ordine degli argomenti nominati 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 con nome kwargs

  • Sequenza dei parametri della funzione:
    1. parametri posizionali
    2. parametro formale che cattura il numero arbitrario di argomenti (prefisso con *)
    3. parametri formali con nome
    4. parametro formale che cattura il numero arbitrario di parametri con nome (prefisso con **)
  • 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 le variabili tuple e dict per gli argomenti personalizzati

Per finire, lasciami anche notare che possiamo passare

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

Quindi la stessa chiamata sopra può essere fatta 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 ** nelle chiamate di funzione sopra. Se li omettiamo, potremmo ottenere risultati malati.

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

La tupla sopra ('custom param1', 'custom param2', 'custom param3') viene stampata così com'è.

Omettere dict args:

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

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg




kwargs