pasar el argumento **kwargs a otra función con **kwargs

2 minutos de lectura

No entiendo el siguiente ejemplo, digamos que tengo estas funciones:

# python likes
def save(filename, data, **kwargs):
    fo = openX(filename, "w", **kwargs) # <- #1
    fo.write(data)
    fo.close()
# python doesnt like
def save2(filename, data, **kwargs):
    fo = openX(filename, "w", kwargs) # <- #2
    fo.write(data)
    fo.close()

def openX(filename, mode, **kwargs):
    #doing something fancy and returning a file object

¿Por qué la #1 es la solución correcta y la #2 la incorrecta? **kwargs es básicamente un dict, así que si quiero pasar el argumento a openX, creo que la forma correcta sería sin ** y simplemente dando el dict. Pero a Python obviamente no le gusta el segundo y me dice que di 3 en lugar de 2 argumentos.

Entonces, ¿cuál es la razón detrás de esto?

  • Me pregunto por qué lo llamas **args en el código. Este es posiblemente el peor nombre posible ya que la gente lo confundirá con *args

    – John LaRooy

    26 de marzo de 2012 a las 6:32

  • Bueno, en realidad nunca uso *args, así que uso **args^^, pero bueno, puedo modificarlo.

    usuario945967

    26 de marzo de 2012 a las 6:34

avatar de usuario
geco

En el segundo ejemplo, proporciona 3 argumentos: nombre de archivo, modo y un diccionario (kwargs). Pero Python espera: 2 argumentos formales más argumentos de palabras clave.

Al prefijar el diccionario con ‘**’, desempaqueta el diccionario kwargs a argumentos de palabras clave.

Un diccionario (tipo dict) es una sola variable que contiene pares clave-valor.

Los “argumentos de palabras clave” son parámetros de método de valor clave.

Cualquier diccionario puede descomprimirse en argumentos de palabras clave prefijándolo con ** durante la llamada de función.

  • Ahora lo entiendo. Pensé que las palabras clave y el dictado eran lo mismo.

    usuario945967

    26 de marzo de 2012 a las 6:41

  • “Cualquier diccionario puede expandirse a palabras clave con el prefijo ** durante la llamada de función”. <- eso es genial

    usuario945967

    26 de marzo de 2012 a las 6:51

  • Ver también: Documentos de Python en parámetros de palabras clave y desempaquetar listas de argumentos

    – dinosaurio

    19/09/2015 a las 17:05

  • Un ejemplo de código real haría esta respuesta considerablemente más clara.

    – perro naranja

    07/12/2017 a las 15:15

Ampliando la respuesta de @gecco, el siguiente es un ejemplo que le mostrará la diferencia:

def foo(**kwargs):
    for entry in kwargs.items():
        print("Key: {}, value: {}".format(entry[0], entry[1]))

# call using normal keys:
foo(a=1, b=2, c=3)
# call using an unpacked dictionary:
foo(**{"a": 1, "b":2, "c":3})

# call using a dictionary fails because the function will think you are
# giving it a positional argument
foo({"a": 1, "b": 2, "c": 3})
# this yields the same error as any other positional argument
foo(3)
foo("string")

Aquí puede ver cómo funciona el desempaquetado de un diccionario y por qué falla el envío de un diccionario real.

los ** la sintaxis le dice a Python que recopile argumentos de palabras clave en un diccionario. los save2 lo está pasando como un argumento que no es una palabra clave (un objeto de diccionario). los openX no está viendo ningún argumento de palabra clave, por lo que el **args no se acostumbra. En cambio, obtiene un tercer argumento que no es una palabra clave (el diccionario). Para arreglar eso, cambie la definición de la openX función.

def openX(filename, mode, kwargs):
    pass

  • Gracias, pero también quiero usar OpenX sin guardar, así que tengo que ceñirme a las palabras clave. Pensé que transmitir palabras clave era básicamente lo mismo que transmitir un dictado, pero no lo sabía hasta ahora 🙂

    usuario945967

    26 de marzo de 2012 a las 6:42

  • @xMRW No pueden ser lo mismo, ya que también puede pasar un diccionario como parámetro a cualquier función. Tu #1 es el correcto entonces.

    – Keith

    26 de marzo de 2012 a las 6:46

avatar de usuario
ElUnoEquipo

Para el n.° 2, los argumentos serán solo un parámetro formal con valor dictado, pero no un parámetro de tipo de palabra clave.

Si desea pasar un parámetro de tipo de palabra clave a un argumento de palabra clave, debe especificar ** antes de su diccionario, lo que significa ** argumentos

consulte esto para obtener más detalles sobre el uso de **kw

http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/

Porque un diccionario es un valor único. Debe usar la expansión de palabras clave si desea pasarlo como un grupo de argumentos de palabras clave.

  • lo siento, pero ¿qué es una “expansión de palabras clave”? ¿Quiere decir que debería usar dict_var en lugar de **args y simplemente usar def func(argument, dict_var=0)…func(1,{1:”a”,2:”b”})

    usuario945967

    26 de marzo de 2012 a las 6:32


avatar de usuario
shahar_m

El siguiente uso de código kwargs y transferirlo a otra función:

def myprint( kwargs ):
    # default values
    a = kwargs.get('a', None)
    b = kwargs.get('b', None)

    # print both
    print('a={}, b={}'.format(a,b))

def mytest( **kwargs ):
    myprint( kwargs )

mytest()
mytest(b=2)

rendimientos:

a=None, b=None
a=None, b=2

  • lo siento, pero ¿qué es una “expansión de palabras clave”? ¿Quiere decir que debería usar dict_var en lugar de **args y simplemente usar def func(argument, dict_var=0)…func(1,{1:”a”,2:”b”})

    usuario945967

    26 de marzo de 2012 a las 6:32


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad