2013-06-01 7 views
14

Je sais quePython `map` et arguments déballer

map(function, arguments) 

est équivalent à

for argument in arguments: 
    function(argument) 

Est-il possible d'utiliser la fonction de carte pour faire ce qui suit?

for arg, kwargs in arguments: 
    function(arg, **kwargs) 
+1

Ces deux choses ne sont pas équivalent. 'map()' construit une liste (ou dans 3.x, un générateur) des valeurs renvoyées à partir des appels de fonction. Si vous ne voulez pas utiliser ces valeurs, n'utilisez pas 'map()', utilisez simplement une boucle normale. –

+5

'map' est une fonction (qui renvoie une liste), et la boucle est un code sans valeur de retour. Ils ne sont pas équivalents. –

Répondre

16

Vous pouvez avec un lambda:

map(lambda a: function(a[0], **a[1]), arguments) 

ou vous pouvez utiliser une expression du générateur ou la compréhension liste, en fonction de ce que vous voulez:

(function(a, **k) for a, k in arguments) 
[function(a, **k) for a, k in arguments] 

En Python 2, map() retours une liste (donc la compréhension de la liste est l'équivalent), en Python 3, map() est un générateur (donc l'expression du générateur peut le remplacer).

Il n'y a pas de méthode de bibliothèque intégrée ou standard qui le fait directement; le cas d'utilisation est trop spécialisé.

0

Vous devez simplement vous rappeler que la carte transmettra les arguments à la fonction sous la forme d'un seul tuple plutôt que d'arguments séparés. Si vous ne pouvez pas changer votre fonction d'origine, vous pouvez l'appeler avec une fonction d'assistance:

def f(tup): 
    args, kwargs = tup 
    function(args, **kwargs) 

map(f, arguments) 
7

Pour le cas des arguments de position seulement, vous pouvez utiliser itertools.starmap(fun, args):

Retour un itérateur dont les valeurs sont renvoyées à partir de la fonction évaluée avec un argument tuple tiré de la séquence donnée.

Exemple:

from itertools import starmap 

def f(i, arg): 
    print(arg * (i+1)) 

for _ in starmap(f, enumerate(["a", "b", "c"])): 
    pass 

impressions:

a 
bb 
ccc 
0

je rencontrais le même besoin et a fini par faire la fonction suivante:

def kwarg_map(element_constructor, **kwarg_lists): 
    """ 
    A helper function for when you want to construct a chain of objects with individual arguments for each one. Can 
    be easier to read than a list expansion. 

    :param element_constructor: A function of the form object = fcn(**kwargs) 
    :param kwarg_lists: A dict of lists, where the index identifies two which element its corresponding value will go. 
    :return: A list of objects. 

    e.g. Initializing a chain of layers: 
     layer_sizes = [784, 240, 240, 10] 
     layers = kwarg_map(
      Layer, 
      n_in = layer_sizes[:-1], 
      n_out = layer_sizes[1:], 
      activation = ['tanh', 'tanh', 'softmax'], 
      ) 

    is equivalent to: 
     layers = [Layer(n_in=784, n_out=240, activation='tanh'), Layer(n_in=240, n_out=240, activation='tanh'), Layer(n_in=240, n_out=10, activation='softmax')] 
    """ 
    all_lens = [len(v) for v in kwarg_lists.values()] 
    assert len(kwarg_lists)>0, "You need to specify at least list of arguments (otherwise you don't need this function)" 
    n_elements = all_lens[0] 
    assert all(n_elements == le for le in all_lens), 'Inconsistent lengths: %s' % (all_lens,) 
    return [element_constructor(**{k: v[i] for k, v in kwarg_lists.iteritems()}) for i in xrange(n_elements)]