Pasar un diccionario a una función como parámetros de palabras clave


346

Me gustaría llamar a una función en python usando un diccionario.

Aquí hay un código:

d = dict(param='test')

def f(param):
    print(param)

f(d)

Esto se imprime {'param': 'test'}pero me gustaría que solo se imprima test.

Me gustaría que funcione de manera similar para más parámetros:

d = dict(p1=1, p2=2)
def f2(p1, p2):
    print(p1, p2)
f2(d)

es posible?

Respuestas:


528

Lo descubrí por mí mismo al final. Es simple, solo me faltaba el operador ** para descomprimir el diccionario

Entonces mi ejemplo se convierte en:

d = dict(p1=1, p2=2)
def f2(p1,p2):
    print p1, p2
f2(**d)

57
si desea que esto ayude a otros, debería reformular su pregunta: el problema no era pasar un diccionario, lo que quería era convertir un dict en parámetros de palabras clave
Javier

11
Vale la pena señalar que también puede descomprimir listas en argumentos posicionales: f2 (* [1,2])
Matthew Trevor

10
"desreferencia": el término habitual, en este contexto de Python, es "desempaquetar". :)
mipadi el

2
Esto es genial, solo lo usé con argparse / __ dict__ para que sea realmente fácil analizar los argumentos de la línea de comandos directamente en las opciones para un objeto de clase.
Horus

1
¿Cuál es la razón por la que nos gustaría desempaquetar un diccionario al pasarlo como argumento a una función?
Mona Jalal

128
In[1]: def myfunc(a=1, b=2):
In[2]:    print(a, b)

In[3]: mydict = {'a': 100, 'b': 200}

In[4]: myfunc(**mydict)
100 200

Algunos detalles adicionales que pueden ser útiles para saber (preguntas que tuve después de leer esto y fui y probé):

  1. La función puede tener parámetros que no están incluidos en el diccionario.
  2. Puede no anular un parámetro que ya está en el diccionario
  3. El diccionario no puede tener parámetros que no estén en la función.

Ejemplos:

Número 1: la función puede tener parámetros que no están incluidos en el diccionario

In[5]: mydict = {'a': 100}
In[6]: myfunc(**mydict)
100 2

Número 2: no puede anular un parámetro que ya está en el diccionario

In[7]: mydict = {'a': 100, 'b': 200}
In[8]: myfunc(a=3, **mydict)

TypeError: myfunc() got multiple values for keyword argument 'a'

Número 3: el diccionario no puede tener parámetros que no estén en la función.

In[9]:  mydict = {'a': 100, 'b': 200, 'c': 300}
In[10]: myfunc(**mydict)

TypeError: myfunc() got an unexpected keyword argument 'c'

Como se solicitó en los comentarios, una solución al Número 3 es filtrar el diccionario en función de los argumentos de palabras clave disponibles en la función:

In[11]: import inspect
In[12]: mydict = {'a': 100, 'b': 200, 'c': 300}
In[13]: filtered_mydict = {k: v for k, v in mydict.items() if k in [p.name for p in inspect.signature(myfunc).parameters.values()]}
In[14]: myfunc(**filtered_mydict)
100 200

Otra opción es aceptar (e ignorar) kwargs adicionales en su función:

In[15]: def myfunc2(a=None, **kwargs):
In[16]:    print(a)

In[17]: mydict = {'a': 100, 'b': 200, 'c': 300}

In[18]: myfunc2(**mydict)
100

Observe más allá de que puede usar argumentos posicionales y listas o tuplas de la misma manera que kwargs, aquí hay un ejemplo más avanzado que incorpora argumentos posicionales y de palabras clave:

In[19]: def myfunc3(a, *posargs, b=2, **kwargs):
In[20]:    print(a, b)
In[21]:    print(posargs)
In[22]:    print(kwargs)

In[23]: mylist = [10, 20, 30]
In[24]: mydict = {'b': 200, 'c': 300}

In[25]: myfunc3(*mylist, **mydict)
10 200
(20, 30)
{'c': 300}

44
Usar el desempaquetado con print.format es particularmente útil. por ejemplo:'hello {greeting} {name}'.format( **{'name': 'Andrew', 'greeting': 'Mr'})
Martlark

Antigua pregunta pero aún muy relevante. Gracias por la respuesta detallada. ¿Conoces alguna forma de evitar el caso 3? ¿Significado mapear pitónicamente los elementos del diccionario a los parámetros de la función, cuando hay más elementos en el diccionario que parámetros?
Spencer

2
@spencer se ha agregado una solución a la respuesta.
David Parks

33

En python, esto se llama "desempaquetar", y puede encontrar un poco al respecto en el tutorial . La documentación de esto apesta, estoy de acuerdo, especialmente por lo fantásticamente útil que es.


20
Es mejor copiar el contenido relevante del enlace en su respuesta, en lugar de confiar en que el enlace sobreviva hasta el final de los tiempos.
Richard

3
@Richard esa es una opinión filosófica profunda sobre la web, ¡con la cual no podría estar más en desacuerdo! Por desgracia, me falta el espacio en este margen aquí para compartir mi maravillosa prueba ...
llimllib

@llimllib, ¡tendré que preguntarle al Dr. Wiles entonces!
Richard

6

Aquí tienes: funciona con cualquier otro iterable:

d = {'param' : 'test'}

def f(dictionary):
    for key in dictionary:
        print key

f(d)

Parece que la gente está rechazando esto, ya que respondió la pregunta original, no la pregunta reformulada. Sugiero simplemente eliminar esta publicación ahora.
dotancohen

@dotancohen no, nunca fue correcto, falla el segundo bloque de código que siempre estaba con la pregunta. Lo tomó demasiado literalmente, la impresión fue un ejemplo.
Dave Hillier

Sin embargo, responde la pregunta, simplemente no lo hace a través del desempaquetado del diccionario. Su enfoque es perfectamente válido según la pregunta publicada.
Natecat
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.