web-dev-qa-db-fra.com

Appeler une fonction avec une liste d'arguments dans python

J'essaie d'appeler une fonction dans une autre fonction en python, mais je ne trouve pas la bonne syntaxe. Ce que je veux faire 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 fonctionnera et le second ne fonctionnera pas. Ce que je veux modifier, c’est la fonction wrapper et non les fonctions appelées.

142
SurDin

Pour développer un peu sur les autres réponses:

Dans la ligne:

def wrapper(func, *args):

Le * à côté de args signifie "prend le reste des paramètres donnés et les place 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" décompressez-la "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 explicitement transmise, mais dans les deux wrappers args contient la liste [1,2,3].

255
itsadok

La manière la plus simple d'envelopper 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 Python, la fonction étant un objet, vous pouvez transmettre son nom en tant qu'argument d'une autre fonction et le renvoyer. Vous pouvez également écrire un générateur de wrapper pour toute 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

Veuillez également noter que, dans Python, lorsque vous ne connaissez pas ou ne souhaitez pas nommer tous les arguments d'une fonction, vous pouvez faire référence à un tuple d'arguments, désigné par son nom, précédé de un astérisque entre parenthèses après le nom de la fonction:

    *args

Par exemple, vous pouvez définir une fonction qui prendrait un nombre quelconque d’arguments:

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

Python permet une manipulation encore plus poussée des arguments de fonction. Vous pouvez autoriser une fonction à prendre des arguments de mots clés. Dans le corps de la fonction, les arguments de mots-clés sont conservés dans un dictionnaire. Entre les parenthèses après le nom de la fonction, ce dictionnaire est désigné par deux astérisques suivis du nom du dictionnaire:

    **kwargs

Un exemple similaire qui affiche le dictionnaire des mots clés:

    def testFunc(**kwargs):
        print kwargs    # prints the dictionary of keyword arguments
18
Alex

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

func(args)

lire

func(*args)

Ceci indique à Python de prendre la liste donnée (dans ce cas, args) et de transmettre son contenu à la fonction sous forme d'arguments de position.

Cette astuce fonctionne des deux "côtés" de l'appel de fonction, donc une fonction définie comme ceci:

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

serait capable d’accepter autant d’arguments de position que vous le feriez et de les placer tous dans une liste appelée args.

J'espère que cela aide à clarifier un peu les choses. Notez que tout cela est également possible avec les arguments dicts/mot-clé, en utilisant ** au lieu de *.

10
Alan Rowarth

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

Que signifient * args et ** kwargs?

Et du tutoriel officiel python

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

10
JimB

Vous devez utiliser des arguments en décompressant ..

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
Joril

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

Voici un petit extrait de code, qui associe lists, Zip() et *args, afin de fournir un wrapper pouvant 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 de contrôle de sécurité pour les listes de longueur inégale, voir Les itérateurs Zip affirmant une longueur égale en python .

0
P. Siehr