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.
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]
.
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
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
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)
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 *
.
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 .