159 votes

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 ça :

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, mais pas le second. Ce que je veux modifier, c'est la fonction enveloppante et non les fonctions appelées.

282voto

itsadok Points 12971

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

Dans la ligne :

def wrapper(func, *args):

L'astérisque (*) à côté de args signifie "prendre le reste des paramètres donnés et les placer dans une liste appelée args ".

Dans la ligne :

    func(*args)

L'astérisque (*) à côté de args signifie ici "prendre cette liste appelée args et la "déballer" dans le reste des paramètres".

Vous pouvez donc procéder comme 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])

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

26 votes

Une chose que je n'ai pas trouvée mentionnée très souvent est la façon d'appeler une fonction avec *args, si vous avez une liste ou un tuple que vous voulez passer. Pour cela, vous devez l'appeler comme ceci : wrapper1(func2, *mylist)

0 votes

*args in def wrapper(func, *args) est ce que method(params object[] args) est en C#.

1 votes

Il convient de noter que *args doit être le dernier argument de la définition de la fonction.

25voto

Alex Points 6025

La façon 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

En Python, une fonction est un objet, vous pouvez donc passer son nom comme argument d'une autre fonction et le retourner. Vous pouvez également é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

Notez également qu'en Python, lorsque vous ne connaissez 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ésigné par son nom, précédé d'un astérisque entre les parenthèses qui suivent 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 permet une manipulation encore plus poussée des arguments des fonctions. Vous pouvez autoriser une fonction à prendre des arguments de type mot-clé. Dans le corps de la fonction, les arguments des mots-clés sont conservés dans un dictionnaire. Dans les parenthèses qui suivent le nom de la fonction, ce dictionnaire est indiqué par deux astérisques suivis du nom du dictionnaire :

    **kwargs

Un exemple similaire qui imprime le dictionnaire des arguments des mots-clés :

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

11voto

JimB Points 9246

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

Que signifient *args et **kwargs ?

Et dans le tutoriel officiel de Python

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

0 votes

J'ai donc besoin qu'il obtienne *args et **kwargs et qu'il l'appelle avec eux ?

1 votes

Non, vous pouvez utiliser l'un ou l'autre, mais ils sont souvent associés. Dans votre cas, vous n'avez besoin que de *args.

0 votes

Ok, ça marche, mais ça ne me permet toujours pas de passer une liste d'arguments, et je dois les passer séparément. Je n'ai pas besoin d'être un expert en la matière, mais j'ai besoin d'un expert en la matière. (Je dois faire wrapper(func2, x, y, z) et non wrapper(func2, [x,y,z]) )

10voto

Alan Rowarth Points 451

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

func(args)

lire

func(*args)

Cela indique à Python de prendre la liste donnée (dans ce cas, args ) et transmet son contenu à la fonction en tant qu'arguments positionnels.

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

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

serait capable d'accepter autant d'arguments positionnels que vous lui lancez, et de les placer tous dans une liste appelée args .

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

8voto

Joril Points 5296

Vous devez utiliser des arguments pour le déballage.

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)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X