Comprensión de kwargs en Python


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

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

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

, ¿Cómo funciona exactamente? ¿Son clases como 'desempaquetar'? Como a,b=1,2?

 660
Author: Blaise, 2009-11-20

10 answers

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 **kwargs cuando llame a 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.

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

 754
Author: Pär Wieslander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-29 23:24:14

Descomprimir diccionarios

** descomprime diccionarios.

Esto

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 empaquetamiento 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 de esta manera:

setstyle(color="red", bold=False)
 286
Author: Georg Schölly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-31 08:34:42

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

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

El qué no es tan simple.

Por ejemplo (muy hipotético) tienes 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 espera un minuto, hay un nuevo parámetro "vehículo" you no lo sabías antes. Ahora debes añadirlo a la firma de la función myDo.

Aquí puedes lanzar kwargs en juego just solo agrega 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 su función de interfaz cada vez que algunas de sus rutinas llamadas puedan cambiar.

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

 59
Author: Juergen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-04 19:08:44

Sobre la base de que una buena muestra a veces es mejor que un discurso largo, escribiré dos funciones usando todas las facilidades de paso de argumentos variables de python (tanto argumentos posicionales como con nombre). Usted debe ser capaz de ver fácilmente lo que hace por sí 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})
 43
Author: kriss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-19 01:12:26

Motif: *args y **kwargs sirve como marcador de posición para los argumentos que deben pasarse a una llamada a 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 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 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

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

 24
Author: kmario23,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-20 14:49:42
  • kwargs en **kwargs es solo el nombre de la variable. Usted puede muy bien tener **anyVariableName
  • kwargs significa "argumentos de palabras clave". Pero creo que es mejor llamarlos como "argumentos nombrados", 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". Supongo que "palabra clave" generalmente significa palabras reservadas por el lenguaje de programación y, por lo tanto, no para ser utilizadas por el programador para nombres de variables. Eso no está pasando aquí en caso de Kwargs.). Así que damos nombres param1 y param2 a dos valores de parámetro pasados a la función de la siguiente manera: func(param1="val1",param2="val2"), en lugar de pasar solo los valores: func(val1,val2). Por lo tanto, creo que deberían llamarse apropiadamente "número arbitrario de argumentos nombrados" ya que podemos especificar cualquier número de estos parámetros (es decir, argumentos) si func tiene firma func(**kwargs)

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

Argumentos con nombre

  • los args con nombre deben seguir a los args posicionales
  • el orden de los args nombrados 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 (con el prefijo *)
    3. nombrado formal parámetros
    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
    

Pasando variables de tupla y dict para args personalizados

Para terminar, permítanme también señalar que podemos pasar {[33]]}

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

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 los argumentos de tupla:

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

Impresiones

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') se imprime como está.

Omitiendo dict args:

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

Da

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg
 17
Author: Mahesha999,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-27 07:03:04

Como adición, 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

 9
Author: philipp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-25 09:45:23

Los Kwargs son un azúcar sintáctico para pasar argumentos de nombre como diccionarios(para func), o diccionarios como argumentos de nombre (para func)

 5
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-20 10:39:06

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 la lista args, o en la lista kwargs, dependiendo de si son argumentos de palabra 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
 5
Author: naught101,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-27 06:15:50

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 para quitar aquí es que el número variable de argumentos nombrados en la llamada se traduce en un diccionario en la función.

 1
Author: user1928764,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-26 21:37:28