¿Cuál es el propósito y uso de ** kwargs?

¿Cuáles son los usos para **kwargs en Python?

Sé que puedes hacer un objeto objects.filter en una tabla y pasar un **kwargs argumento de **kwargs .

¿También puedo hacer esto para especificar deltas de tiempo, es decir, timedelta(hours = time1) ?

¿Cómo funciona exactamente? ¿Se trata de clases como ‘desembalaje’? Como a,b=1,2 ?

Puede usar **kwargs para permitir que sus funciones tomen un número arbitrario de argumentos de palabras clave (“kwargs” significa “argumentos de palabras clave”):

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

También puede usar la syntax de **kwargs al llamar a funciones mediante la construcción de un diccionario de argumentos de palabras clave y pasarlo a su función:

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

El Tutorial de Python contiene una buena explicación de cómo funciona, junto con algunos buenos ejemplos.

<--Actualizar-->

Para las personas que usan Python 3, en lugar de iteritems (), use items ()

Desembalar diccionarios

** desempaqueta los diccionarios.

Esta

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

es lo mismo que

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

Es útil si tienes que construir parámetros:

 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) 

Parámetros de embalaje de una función.

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

Esto te permite usar la función así:

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

Kwargs es solo un diccionario que se agrega a los parámetros.

Un diccionario puede contener claves, pares de valores. Y esos son los kwargs. Ok, así es como.

El Whatfor no es tan simple.

Por ejemplo (muy hipotético) tiene una interfaz que simplemente llama a otras rutinas para hacer el trabajo:

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

Ahora obtienes un nuevo método “drive”:

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

Pero espere un minuto, hay un nuevo parámetro “vehículo”: no lo sabía antes. Ahora debes agregarlo a la firma de la función myDo.

Aquí puedes poner a los kwargs en juego; solo tienes que añadirlos a la firma:

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

De esta manera, no necesita cambiar la firma de su función de interfaz cada vez que cambien algunas de sus rutinas llamadas.

Este es solo un buen ejemplo que podría encontrar útil a los kwargs.

Sobre la base de que una buena muestra a veces es mejor que un discurso largo, escribiré dos funciones utilizando todas las facilidades de paso de argumentos de las variables de Python (tanto posicionales como argumentos con nombre). Deberías poder ver fácilmente lo que hace por ti mismo:

 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) 

Y aquí está la salida:

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

Motif: *args y **kwargs sirve como marcador de posición para los argumentos que deben pasarse a una llamada de función

usando *args y **kwargs para llamar a una función

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

Ahora usaremos *args para llamar a la función definida arriba

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

resultado:

arg1: dos
arg2: 3
arg3: 5


Ahora, usando **kwargs para llamar a la misma función

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

resultado:

arg1: 5
arg2: dos
arg3: 3

En pocas palabras: *args no tiene inteligencia, simplemente interpola los argumentos pasados ​​a los parámetros (en orden de izquierda a derecha) mientras que **kwargs comporta de manera inteligente al colocar el valor apropiado @ el lugar requerido

  • kwargs en **kwargs es solo un nombre variable. Usted puede tener muy bien **anyVariableName
  • kwargs significa “argumentos de palabras clave”. Pero creo que es mejor que se llamen “argumentos con nombre”, ya que son simples argumentos que se pasan junto con los nombres (no encuentro ningún significado para la palabra “palabra clave” en el término “palabra clave”. Supongo que “palabra clave” generalmente significa palabras reservadas por el lenguaje de progtwigción y, por lo tanto, no deben ser usadas por el progtwigdor para nombres de variables. No ocurre nada aquí en el caso de kwargs). Entonces, param2 a los parámetros param1 y param2 dos valores de parámetros pasados ​​a la función de la siguiente manera: func(param1="val1",param2="val2") , en lugar de pasar solo valores: func(val1,val2) . Por lo tanto, creo que deberían llamarse apropiadamente “número arbitrario de argumentos con nombre”, ya que podemos especificar cualquier número de estos parámetros (es decir, argumentos) si func tiene una func(**kwargs) firma func(**kwargs)

Dicho esto, permítanme explicar primero “argumentos con nombre” y luego “número arbitrario de argumentos con nombre” kwargs .

Argumentos con nombre

  • args nombrados deben seguir args posicionales
  • orden de args nombrado no es importante
  • Ejemplo

     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' 

Número arbitrario de argumentos nombrados kwargs

  • Secuencia de parámetros de función:
    1. parámetros posicionales
    2. Parámetro formal que captura un número arbitrario de argumentos (con el prefijo *)
    3. parámetros formales nombrados
    4. parámetro formal que captura el número arbitrario de parámetros nombrados (prefijados con **)
  • Ejemplo

     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 

Pasando las variables tupla y dict para args personalizados

Para terminar, permítanme señalar también que podemos pasar.

  • “parámetro formal que captura un número arbitrario de argumentos” como variable de tupla y
  • “Parámetro formal que captura el número arbitrario de parámetros nombrados” como variable dict

Así, la misma llamada anterior se puede hacer de la siguiente manera:

 tupleCustomArgs = ("custom param1", "custom param2", "custom param3") dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"} function2("arg1", *tupleCustomArgs, #note * param3="arg3", param2="arg2", **dictCustomNamedArgs #note ** ) 

Por último nota * y ** en las llamadas de función anteriores. Si los omitimos, podemos obtener malos resultados.

Omitiendo * en arglas tupla:

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

huellas dactilares

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

Sobre la tupla ('custom param1', 'custom param2', 'custom param3') se imprime como está.

Omitiendo los dict arg

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

da

 dictCustomNamedArgs ^ SyntaxError: non-keyword arg after keyword arg 

Como adición, también puede combinar diferentes formas de uso al llamar a las funciones de kwargs:

 def test(**kwargs): print kwargs['a'] print kwargs['b'] print kwargs['c'] args = { 'b': 2, 'c': 3} test( a=1, **args ) 

da esta salida:

 1 2 3 

Tenga en cuenta que ** kwargs tiene que ser el último argumento

los kwargs son un azúcar sintáctico para pasar argumentos de nombre como diccionarios (para func) o diccionarios como argumentos con nombre (para func)

Aquí hay una función simple que sirve para explicar el uso:

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

Cualquier argumento que no esté especificado en la definición de la función se colocará en la lista de kwargs , o en la lista de kwargs , dependiendo de si son argumentos de palabras clave o no:

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

Si agrega un argumento de palabra clave que nunca se pasa a una función, se generará un error:

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

Aquí hay un ejemplo que espero sea útil:

 #! /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] ) 

Cuando ejecutas el progtwig, obtienes:

 $ 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 clave aquí es que la cantidad variable de argumentos con nombre en la llamada se traduce en un diccionario en la función.