Appeler une fonction avec une liste d'arguments en python

j'essaie d'appeler une fonction à l'intérieur d'une autre fonction en python, mais je ne trouve pas la bonne syntaxe. Ce que je veux faire, c'est quelque chose comme ceci:

def wrapper(func, args):
    func(args)

def func1(x):
    print(x)

def func2(x, y, z):
    return x+y+z

wrapper(func1, [x])
wrapper(func2, [x, y, z])

dans ce cas, le premier appel marchera, et le second ne marchera pas. Ce que je veux modifier est la fonction wrapper et pas les fonctions appelées.

128
demandé sur SilentGhost 2009-05-03 17:43:33

6 réponses

De développer un peu sur l'autre répond:

dans la ligne:

def wrapper(func, *args):

* args signifie "prendre le reste de paramètres et de les mettre dans une liste appelée args ".

dans la ligne:

    func(*args)

le * à côté de args signifie ici" prenez cette liste appelée args et 'unwrap' elle dans le reste des paramètres.

donc vous pouvez faire ce qui suit:

def wrapper1(func, *args): # with star
    func(*args)

def wrapper2(func, args): # without star
    func(*args)

def func2(x, y, z):
    print x+y+z

wrapper1(func2, 1, 2, 3)
wrapper2(func2, [1, 2, 3])

Dans wrapper2 , la liste est transmise explicitement, mais dans les deux wrappers args contient la liste [1,2,3] .

235
répondu itsadok 2009-05-03 15:17:44

La plus simple façon d'enrouler une fonction

    func(*args, **kwargs)

... est d'écrire manuellement un wrapper qui appellerait func () à l'intérieur de lui-même:

    def wrapper(*args, **kwargs):
        # do something before
        try:
            return func(*a, **kwargs)
        finally:
            # do something after

dans la fonction Python est un objet, donc vous pouvez passer son nom comme argument d'une autre fonction et le retourner. Vous pouvez aussi écrire un générateur d'enveloppe pour n'importe quelle fonction anyFunc () :

    def wrapperGenerator(anyFunc, *args, **kwargs):
        def wrapper(*args, **kwargs):
            try:
                # do something before
                return anyFunc(*args, **kwargs)
            finally:
                #do something after
        return wrapper

s'il vous Plaît aussi notez que dans Python quand vous ne savez pas ou ne voulez pas nommer tous les arguments d'une fonction, vous pouvez vous référer à un tuple d'arguments, qui est dénoté par son nom, précédé d'un astérisque dans les parenthèses après le nom de la fonction:

    *args

par exemple, vous pouvez définir une fonction qui prendrait n'importe quel nombre d'arguments:

    def testFunc(*args):
        print args    # prints the tuple of arguments

Python prévoit encore plus de manipulation sur les arguments de fonction. Vous pouvez permettre à une fonction de prendre mot-clé arguments. Dans le corps de fonction les arguments de mot-clé sont tenus dans un dictionnaire. Dans les parenthèses après le nom de la fonction ce dictionnaire est dénoté par deux astérisques suivis du nom du dictionnaire:

    **kwargs

un exemple similaire qui imprime les mots-clés arguments dictionary:

    def testFunc(**kwargs):
        print kwargs    # prints the dictionary of keyword arguments
16
répondu Alex 2018-02-24 15:18:15

vous pouvez utiliser la syntaxe *args et * * kwargs pour les arguments de longueur variable.

que signifient *args et * * kwargs?

et du tutoriel officiel de python

http://docs.python.org/dev/tutorial/controlflow.html#more-on-defining-functions

10
répondu JimB 2017-05-23 12:34:41

vous devez utiliser des arguments pour déballer..

def wrapper(func, *args):
    func(*args)

def func1(x):
    print(x)

def func2(x, y, z):
    print x+y+z

wrapper(func1, 1)
wrapper(func2, 1, 2, 3)
8
répondu Joril 2009-05-03 13:53:57

la réponse littérale à votre question (faire exactement ce que vous avez demandé, changer seulement l'enveloppe, pas les fonctions ou les appels de fonction) est simplement de modifier la ligne

func(args)

pour lire

func(*args)

indique à Python de prendre la liste donnée (dans ce cas, args ) et de passer son contenu à la fonction comme argument de position.

cette astuce fonctionne sur les deux "côtés" de l'appel de fonction, donc un fonction définie comme suit:

def func2(*args):
    return sum(args)

serait en mesure d'accepter autant d'arguments de position comme vous le lancez, et les placer dans une liste appelée args .

j'espère que cela aidera à clarifier les choses un peu. Notez que tout cela est également possible avec les arguments dicts/keyword, en utilisant ** au lieu de * .

8
répondu Alan Rowarth 2009-05-03 19:48:20

un petit ajout aux réponses précédentes, car je ne pouvais pas trouver une solution à un problème, ce qui n'est pas la peine d'ouvrir une nouvelle question, mais m'a conduit ici.

voici un petit extrait de code, qui combine lists , zip() et *args , pour fournir un wrapper qui peut traiter un nombre inconnu de fonctions avec un nombre inconnu d'arguments.

def f1(var1, var2, var3):
    print(var1+var2+var3)

def f2(var1, var2):
    print(var1*var2)

def f3():
    print('f3, empty')

def wrapper(a,b, func_list, arg_list):
    print(a)
    for f,var in zip(func_list,arg_list):
        f(*var)
    print(b)

f_list = [f1, f2, f3]
a_list = [[1,2,3], [4,5], []]

wrapper('begin', 'end', f_list, a_list)

gardez à l'esprit que zip() ne fournit pas un contrôle de sécurité pour les listes de longueur inégale, voir zip itérateurs affirmant pour l'égalité de longueur en python .

0
répondu P. Siehr 2017-05-23 12:03:08