variable - Entendiendo kwargs en Python
python 3.6*args (10)
¿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
?
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)
Aquí hay un ejemplo que espero que 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 programa, 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.
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 se especifique 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
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
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.
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 sintaxis de **kwargs
al llamar a funciones mediante la construcción de un diccionario de argumentos de palabras clave y pasándolo 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 ()
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 la variable 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})
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)
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 el 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 simplemente argumentos que se pasan junto con los nombres (no encuentro ningún significado para la palabra "palabra clave" en el término "argumentos de palabra clave". Supongo que "palabra clave" generalmente significa palabras reservadas por el lenguaje de programación y, por lo tanto, no deben ser utilizadas por el programador para nombres de variables. No ocurre nada de esto en el caso de kwargs. Por lo tanto,param1
nombresparam1
yparam2
a 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) sifunc
tiene unafunc(**kwargs)
firmafunc(**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:
- parámetros posicionales
- Parámetro formal que captura un número arbitrario de argumentos (con el prefijo *)
- parámetros formales nombrados
- 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 **
)
Finalmente 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