Pregunta Comprender kwargs en Python


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

Sé que puedes hacer un objects.filter en una mesa y pase en una **kwargs argumento.

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

¿Cómo funciona exactamente? ¿Son las clases como 'desempacar'? Me gusta a,b=1,2?


643
2017-11-20 09:40


origen


Respuestas:


Puedes usar **kwargs para permitir que sus funciones tomen un número arbitrario de argumentos de palabra clave ("kwargs" significa "argumentos de palabra 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 puedes usar el **kwargs sintaxis al llamar funciones al construir un diccionario de argumentos de palabra clave y pasarlo a su función:

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

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

<- Actualización ->

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


729
2017-11-20 09:58



Desempaquetar diccionarios

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

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

278
2017-11-20 09:59



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 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": usted no lo sabía antes. Ahora debe agregarlo a la firma de la función myDo.

Aquí puedes lanzar Kwargs en juego: simplemente agregas 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 forma, 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 ayudar a los kwargs.


57
2017-11-20 09:51



Sobre la base de que una buena muestra es a veces mejor que un discurso largo, escribiré dos funciones utilizando todas las facilidades de paso de argumentos variables de Python (argumentos posicionales y con nombre). 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})

40
2018-01-24 16:56



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

utilizando *args y **kwargs llamar a una función

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

Ahora usaremos *args 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 **kwargs 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

Línea de fondo : *args no tiene inteligencia, simplemente interpola los argumentos pasados ​​a los parámetros (en orden de izquierda a derecha) mientras **kwargs se comporta inteligentemente colocando el valor apropiado en el lugar requerido


21
2018-01-06 06:57



  • kwargs en **kwargs es solo el nombre de la variable. Puedes muy bien tener **anyVariableName
  • kwargs significa "argumentos de palabra clave". Pero creo que deberían llamarse como "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 palabra clave". Creo 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 los nombres de las variables. Tal cosa no está sucediendo aquí en el caso de los kwargs). Entonces damos nombres param1 y param2a 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 nombrados" ya que podemos especificar cualquier cantidad de estos parámetros (es decir, argumentos) si func tiene firma func(**kwargs)

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

Argumentos con nombre

  • Args nombrados deben seguir argumentos posicionales
  • orden de 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 el número arbitrario de argumentos (prefijado con *)
    3. parámetros formales nombrados
    4. parámetro formal que captura el número arbitrario de parámetros nombrados (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
    

Pasar variables tuple y dict para argumentos personalizados

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

  • "parámetro formal que captura el número arbitrario de argumentos" como variable tupla y
  • "parámetro formal que captura el número arbitrario de parámetros nombrados" 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 note * y ** en llamadas a funciones anteriores. Si los omitimos, podemos obtener malos resultados.

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

Por encima de la tupla ('custom param1', 'custom param2', 'custom param3') está impreso como está.

Omitir dict args:

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

da

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg

16
2017-09-20 07:19



Como complemento, también puede mezclar diferentes formas de uso al llamar a las funciones 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


9
2018-02-25 09:45



Los kwargs son un azucar sintáctico para pasar argumentos de nombres como diccionarios (para func), o diccionarios como argumentos con nombre (a func)


5
2017-11-20 10:39



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 sea no especificado en la definición de la función se pondrá en el args lista, o el kwargs lista, dependiendo de si son argumentos 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 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

5
2017-11-27 06:15