2017-07-03 1 views
6

J'ai ensembles de valeurs que je veux appliquer en tant que paramètres à une fonction:Exécuter fonction sur toutes les combinaisons possibles de paramètres

params = { 
    'a': [1, 2, 3], 
    'b': [5, 6, 7], 
    'x': [None, 'eleven', 'f'], 
    # et cetera 
} 

Je veux courir myfunc() avec toutes les combinaisons possibles, donc myfunc(a=1, b=5, x=None ...), myfunc(a=2, b=5, x=None ...) .. myfunc(a=3, b=7, x='f' ...). Y at-il quelque chose (par exemple dans itertools) qui peut aider? J'ai pensé utiliser itertools.product() mais cela ne garde pas les noms des paramètres et me donne juste des tuples des combinaisons.

Répondre

5

Vous pouvez utiliser itertools.product pour obtenir toutes les combinaisons d'arguments:

>>> import itertools 
>>> for xs in itertools.product([1,2], [5,6], ['eleven', 'f']): 
...  print(xs) 
... 
(1, 5, 'eleven') 
(1, 5, 'f') 
(1, 6, 'eleven') 
(1, 6, 'f') 
(2, 5, 'eleven') 
(2, 5, 'f') 
(2, 6, 'eleven') 
(2, 6, 'f') 

Avec Argument list unpacking, vous pouvez appeler myfunc avec toutes les combinaisons d'arguments mot-clé:

params = { 
    'a': [1, 2, 3], 
    'b': [5, 6, 7], 
    'x': [None, 'eleven', 'f'], 
} 

def myfunc(**args): 
    print(args) 

import itertools 
keys = list(params) 
for values in itertools.product(*map(params.get, keys)): 
    myfunc(**dict(zip(keys, values))) 

sortie:

{'a': 1, 'x': None, 'b': 5} 
{'a': 1, 'x': None, 'b': 6} 
{'a': 1, 'x': None, 'b': 7} 
{'a': 1, 'x': 'eleven', 'b': 5} 
{'a': 1, 'x': 'eleven', 'b': 6} 
{'a': 1, 'x': 'eleven', 'b': 7} 
{'a': 1, 'x': 'f', 'b': 5} 
... 
+0

C'est très chouette! Je suis préoccupé par le fait que l'ordre soit éteint, puisque les dicts ne sont pas ordonnés (non?). Cela pourrait signifier que 'itertools.product()' renvoie les paramètres dans un ordre différent de celui des clés, ce qui entraînerait une discordance. – Bluefire

+0

@Bluefire, 'myfunc (a = 1, b = 2, c = 3)', 'myfunc (b = 2, c = 3, a = 1)' les deux sont corrects. – falsetru

+2

'map (params.get, keys)' est une façon inutilement verbeuse d'écrire 'params.values ​​()' ici; il est garanti que '.keys()' et '.values ​​()' s'aligneront sauf si le dictionnaire est modifié. – DSM

3

Commande de .keys et .values sont garantis dans toutes les versions de Python (sauf si dict est modifié qui ne se fait pas ici), alors cela pourrait être un peu trivial:

from itertools import product 

for vals in product(*params.values()): 
    myfunc(**dict(zip(params, vals))) 

Vous pouvez trouver le gurantee dans le docs:

Si les clés, les valeurs et les vues d'éléments sont itérées sans modification du dictionnaire, l'ordre des éléments correspondra directement à .


Demo:

for vals in product(*params.values()): 
    print(dict(zip(params, vals))) 

{'a': 1, 'x': None, 'b': 5} 
{'a': 1, 'x': None, 'b': 6} 
{'a': 1, 'x': None, 'b': 7} 
{'a': 1, 'x': 'eleven', 'b': 5} 
{'a': 1, 'x': 'eleven', 'b': 6} 
{'a': 1, 'x': 'eleven', 'b': 7} 
{'a': 1, 'x': 'f', 'b': 5} 
{'a': 1, 'x': 'f', 'b': 6} 
{'a': 1, 'x': 'f', 'b': 7} 
... 
+2

Peut-être ajouter un lien vers la [garantie] (https://docs.python.org/3/library/stdtypes.html # dictionary-view-objects)? – DSM

+2

@DSM Oui monsieur, inclus. Merci. –