Passer un dictionnaire à une fonction en tant que paramètres de mot-clé


346

Je voudrais appeler une fonction en python à l'aide d'un dictionnaire.

Voici du code:

d = dict(param='test')

def f(param):
    print(param)

f(d)

Ceci imprime {'param': 'test'} mais j'aimerais qu'il imprime test.

J'aimerais qu'il fonctionne de la même manière pour plus de paramètres:

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

Est-ce possible?

Réponses:


528

Je l'ai compris pour moi à la fin. C'est simple, il me manquait juste l'opérateur ** pour déballer le dictionnaire

Mon exemple devient donc:

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

57
si vous voulez que cela aide les autres, vous devriez reformuler votre question: le problème ne passait pas un dictionnaire, ce que vous vouliez était de transformer un dict en paramètres de mot-clé
Javier

11
Il convient de noter que vous pouvez également décompresser des listes en arguments positionnels: f2 (* [1,2])
Matthew Trevor

10
"dereference": le terme usuel, dans ce contexte Python, est "unpack". :)
mipadi

2
C'est génial, il suffit de l'utiliser avec argparse / __ dict__ pour simplifier l'analyse d'arguments en ligne de commande directement dans les options d'un objet de classe.
Horus

1
quelle est la raison pour laquelle nous voudrions décompresser un dictionnaire en le passant comme argument à une fonction?
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

Quelques détails supplémentaires qui pourraient être utiles à savoir (questions que j'avais après avoir lu ceci et qui sont allées et testées):

  1. La fonction peut avoir des paramètres qui ne sont pas inclus dans le dictionnaire
  2. Vous ne pouvez pas remplacer un paramètre qui est déjà dans le dictionnaire
  3. Le dictionnaire ne peut pas avoir de paramètres qui ne figurent pas dans la fonction.

Exemples:

Numéro 1: la fonction peut avoir des paramètres qui ne sont pas inclus dans le dictionnaire

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

Numéro 2: vous ne pouvez pas remplacer un paramètre qui est déjà dans le dictionnaire

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

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

Numéro 3: Le dictionnaire ne peut pas avoir de paramètres qui ne sont pas dans la fonction.

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

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

Comme demandé dans les commentaires, une solution au numéro 3 consiste à filtrer le dictionnaire en fonction des arguments de mots clés disponibles dans la fonction:

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

Une autre option consiste à accepter (et à ignorer) les kwargs supplémentaires dans votre fonction:

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

Remarquez plus loin que vous pouvez utiliser des arguments positionnels et des listes ou des tuples de la même manière que les kwargs, voici un exemple plus avancé incorporant à la fois des arguments positionnels et des arguments de mots clés:

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}

4
L'utilisation du déballage avec print.format est particulièrement utile. par exemple:'hello {greeting} {name}'.format( **{'name': 'Andrew', 'greeting': 'Mr'})
Martlark

Vieille question mais toujours très pertinente. Merci pour la réponse détaillée. Connaissez-vous des moyens de contourner le cas 3? Signification mapper de manière pythonique les éléments du dictionnaire aux paramètres de la fonction, lorsqu'il y a plus d'éléments dans le dictionnaire qu'il n'y a de paramètres?
spencer le

2
@spencer une solution a été ajoutée à la réponse.
David Parks

33

En python, cela s'appelle "décompresser", et vous pouvez en trouver un peu dans le tutoriel . La documentation est nul, je suis d'accord, surtout à cause de son utilité fantasmatique.


20
Il est préférable de copier le contenu pertinent du lien dans votre réponse, plutôt que de compter sur le lien survivant jusqu'à la fin des temps.
Richard

3
@Richard c'est une opinion philosophique profonde sur le web, avec laquelle je ne pourrais pas être plus en désaccord! Hélas, je manque d'espace dans cette marge pour partager ma merveilleuse preuve ...
llimllib

@llimllib, je devrai alors demander au Dr Wiles!
Richard

6

Et voilà - fonctionne comme n'importe quel autre itérable:

d = {'param' : 'test'}

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

f(d)

Il semble que les gens votent contre cela car il a répondu à la question d'origine, pas à la question reformulée. Je suggère de supprimer ce post maintenant.
dotancohen du

@dotancohen non il n'a jamais été correct, il échoue au deuxième bloc de code qui était toujours à la question. Il l'a pris trop à la lettre, l'impression en était un exemple.
Dave Hillier

Il répond cependant à la question, il ne le fait tout simplement pas via le déballage du dictionnaire. Son approche est parfaitement valable sur la base de la question posée.
Natecat
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.