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

763

¿Para qué sirven **kwargsen Python?

Sé que puedes hacer un objects.filtersobre una mesa y pasar una **kwargsdiscusión.  

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

¿Cómo funciona exactamente? ¿Es clases como 'desempaquetar'? Al igual que a,b=1,2?

Federer
fuente
27
Si te topas con esta pregunta como yo, mira también: * args y ** kwargs?
Sumid
3
Una explicación notablemente concisa aquí : "* recopila todos los argumentos posicionales en una tupla", "** recopila todos los argumentos de palabras clave en un diccionario". La palabra clave es recolecta .
osa
24
Solo para su información: kwargssignifica KeyWord ARGumentS, es decir, argumentos que han establecido claves
Richard de Wit

Respuestas:

868

Puede usar **kwargspara permitir que sus funciones tomen una cantidad arbitraria 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 **kwargssintaxis al invocar funciones construyendo 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 ()

Pär Wieslander
fuente
1
@ yashas123 No; si recorre algo que está vacío, no pasa nada, por lo que cualquier código que venga después se ejecuta normalmente.
JG
330

Desembalaje de diccionarios

** desempaqueta 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 tiene 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 le permite usar la función de esta manera:

setstyle(color="red", bold=False)
Georg Schölly
fuente
13
es kwarg es solo un nombre de variable ¿verdad? entonces puedo usar def func (** args): ¿y funcionaría?
Sriram
11
@Sriram: Correcto. Los asteriscos son importantes. kwargs es solo el nombre que se le da si no hay nada mejor. (Por lo general, hay.)
Georg Schölly
54
@Sriram: por razones de legibilidad, debe atenerse a los kwargs ; otros programadores lo apreciarán.
johndodo
12
** do unpack dictionaries.>> alucinante / por supuesto! +1 por explicar ese bit.
Marc
13
Nota: .iteritems()ha sido renombrado .items()en Python 3.
fnkr
67

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

Un diccionario puede contener pares clave, valor. Y esos son los kwargs. Ok, así es como.

El para qué no es tan simple.

Por ejemplo (muy hipotético) tiene una interfaz que solo 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 debe agregarlo a la firma de la función myDo.

Aquí puedes lanzar kwargs al juego; solo tienes que agregar kwargs 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 la función de su interfaz cada vez que cambien algunas de sus rutinas llamadas.

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

Juergen
fuente
46

Sobre la base de que una buena muestra es a veces mejor que un discurso largo, escribiré dos funciones usando todas las facilidades de paso de argumentos variables de Python (tanto argumentos posicionales como nombrados). Debería poder ver fácilmente lo que hace usted 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á el resultado:

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})
kriss
fuente
28

Motivo: *argsy **kwargssirve como marcador de posición para los argumentos que deben pasarse a una llamada de función

usando *argsy **kwargspara llamar a una función

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

Ahora usaremos *argspara llamar a la función definida anteriormente

#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 **kwargspara 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 *argspocas palabras : no tiene inteligencia, simplemente interpola los argumentos pasados ​​a los parámetros (en orden de izquierda a derecha) mientras se **kwargscomporta de manera inteligente colocando el valor apropiado en el lugar requerido

kmario23
fuente
24
  • kwargsen **kwargses solo un nombre variable. Puedes muy bien tener**anyVariableName
  • kwargssignifica "argumentos de palabras clave". Pero creo que es mejor llamarlos "argumentos con nombre", ya que estos son simplemente argumentos pasados ​​junto con nombres (no encuentro ningún significado para la palabra "palabra clave" en el término "argumentos de palabras 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. Aquí no sucede tal cosa en el caso de kwargs). Por lo que damos nombres param1y param2a dos valores de los parámetros pasados a la función de la siguiente manera: func(param1="val1",param2="val2")en lugar de pasar sólo valores: func(val1,val2). Por lo tanto, creo que deberían llamarse adecuadamente "número arbitrario de argumentos con nombre", ya que podemos especificar cualquier número de estos parámetros (es decir,funcfunc(**kwargs)

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

Argumentos nombrados

  • los args nombrados deben seguir los args posicionales
  • el orden de los args con nombre 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 un número arbitrario de parámetros con nombre (con el prefijo **)
  • 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 variables tuple y dict para argumentos personalizados

Para terminar, déjame también notar que podemos pasar

  • "parámetro formal que captura un número arbitrario de argumentos" como variable de tupla y
  • "parámetro formal que captura un número arbitrario de parámetros con nombre" como variable dict

Por lo tanto, 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, tenga en cuenta *y **en las llamadas a funciones anteriores. Si los omitimos, podemos obtener malos resultados.

Omitiendo *en tuple args:

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

La tupla anterior ('custom param1', 'custom param2', 'custom param3')se imprime tal como está.

Omitiendo dictargs:

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

da

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg
Mahesha999
fuente
3
Me imagino que la keywordterminología proviene del hecho de que está pasando un dict que es una base de datos de pares clave-valor.
crobar
¿Te refieres a la palabra "clave" en los pares de valores "clave"? Además, generalmente no se llama base de datos, sino diccionario. Pero aún no puede encontrar ningún significado para el uso de la palabra "palabra clave".
Mahesha999
9

Además, también puede mezclar 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

philipp
fuente
5

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)


fuente
5

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 argslista, o en la kwargslista, 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
nada101
fuente
1

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 ejecuta el programa, obtiene:

$ 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 el número variable de argumentos nombrados en la llamada se traduce en un diccionario en la función.

usuario1928764
fuente
0

Este es el ejemplo simple para entender sobre el desempaquetado de 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
Mohideen bin Mohammed
fuente
0

En Java, usa constructores para sobrecargar clases y permitir múltiples parámetros de entrada. En python, puede usar kwargs para proporcionar un comportamiento similar.

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

ejemplo de 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 otra forma de pensarlo.

Aidan Melen
fuente
0

Los argumentos de palabras clave a menudo se acortan a kwargs en Python. En programación de computadoras ,

Los argumentos de palabras clave se refieren al soporte de un lenguaje de computadora para llamadas a funciones que establecen claramente el nombre de cada parámetro dentro de la llamada a funciones.

El uso de los dos asteriscos antes del nombre del parámetro, ** kwargs , es cuando uno no sabe cuántos argumentos de palabras clave se pasarán a la función. Cuando ese es el caso, se llama Arbitrary / Wildcard Keyword Arguments.

Un ejemplo de esto son las funciones del receptor de Django .

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

Observe que la función toma un argumento de remitente, junto con argumentos de palabras clave comodín (** kwargs); Todos los manejadores de señales deben tomar estos argumentos. Todas las señales envían argumentos de palabras clave y pueden cambiar esos argumentos de palabras clave en cualquier momento. En el caso de request_finished , se documenta que no envía argumentos, lo que significa que podríamos sentir la tentación de escribir nuestro manejo de señal como my_callback (remitente).

Esto estaría mal; de hecho, Django arrojará un error si lo hace. Esto se debe a que en cualquier momento los argumentos pueden agregarse a la señal y su receptor debe ser capaz de manejar esos nuevos argumentos.

Tenga en cuenta que no tiene que llamarse kwargs , pero debe tener ** (el nombre kwargs es una convención).

Tiago Martins Peres 李大仁
fuente