2009-05-03 29 views
126

Estoy tratando de llamar a una función dentro de otra función en python, pero no puedo encontrar la sintaxis correcta. Lo que quiero hacer es algo como esto:Llamar a una función con lista de argumentos en python

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

En este caso, la primera llamada funcionará y la segunda no. Lo que quiero modificar es la función contenedora y no las funciones llamadas.

Respuesta

225

Para ampliar un poco en las otras respuestas:

En th Línea E:

def wrapper(func, *args): 

El * junto a args significa "tomar el resto de los parámetros dados y las puso en una lista llamada args".

En la línea:.

func(*args) 

El * junto a args aquí significa "tomar esta lista llamados argumentos y 'Separar' en el resto de los parámetros

para que pueda hacer lo siguiente :

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 lista se pasa de forma explícita, pero en ambos envoltorios args contiene la lista [1,2,3].

+20

Una cosa que no he mencionado muy a menudo es cómo llamar a una función con * args, si tiene una lista o tupla que desea pasar. Para eso necesitas llamarlo así: wrapper1 (func2, * mylist) – pug

+0

* args en 'def wrapper (func, * args)' es qué 'método (params object [] args)' está en C#. –

+0

Tenga en cuenta que '* args' debe ser el último argumento en la definición de la función. –

10

Puede usar * args y ** sintaxis kwargs para argumentos de longitud variable.

What do *args and **kwargs mean?

Y desde el tutorial de Python oficial

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

+0

¿Debo obtener tanto * args como ** kwargs y llamarlo con ellos? – SurDin

+1

No, puede usar cualquiera de las dos opciones, pero a menudo se combinan entre sí. En tu caso, solo necesitas * args. – JimB

+0

Ok, funciona, pero todavía no me deja pasar una lista de argumentos, y tengo que pasarlos por separado. No me molesta mucho, en mi situación actual, pero aún sería bueno saber cómo hacer esto. (Necesito hacer el contenedor (func2, x, y, z) y no el contenedor (func2, [x, y, z])) – SurDin

8

Es necesario utilizar argumentos desembalaje ..

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

La respuesta literal a su pregunta (para hacer exactamente lo que usted pidió, cambiando sólo la envoltura, no las funciones o las llamadas de función) es simplemente para alterar la línea

func(args) 

leer

func(*args) 

Esto le dice a Python que tome la lista dada (en este caso, args) y pase su contenido a la función como argumentos posicionales.

Este truco funciona en ambos "lados" de la llamada de función, por lo que una función definida de esta manera:

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

sería capaz de aceptar tantos argumentos posicionales como que lanzar en él, y colocarlos todos en una lista llamada args.

Espero que esto ayude a aclarar un poco las cosas. Tenga en cuenta que esto también es posible con argumentos dictados/palabras clave, usando ** en lugar de *.

15

La manera más simple para envolver una función

func(*args, **kwargs) 

... es escribir manualmente un envoltorio que llamar func() dentro de sí mismo:

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

En función de Python es una objeto, por lo que puede pasar su nombre como argumento de otra función y devolverlo. También puede escribir un generador de envolvente para cualquier función anyFunc():

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

Tenga en cuenta también que en Python cuando no sabe o no quiere nombrar a todos los argumentos de una función, puede referirse a una tupla de argumentos, que se denota por su nombre, precedido por un asterisco en los paréntesis después del nombre de la función:

*args 

por ejemplo, puede definir una función que tomar cualquier número de argumentos:

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

Python proporciona una manipulación aún mayor en los argumentos de la función. Puede permitir que una función tome argumentos de palabra clave. Dentro del cuerpo de la función, los argumentos de la palabra clave se mantienen en un diccionario. En los paréntesis después del nombre de la función de este diccionario se denota por dos asteriscos, seguido por el nombre del diccionario:

**kwargs 

Un ejemplo similar que imprime el diccionario de argumentos de palabra clave:

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

Una pequeña adición a respuestas anteriores, ya que no pude encontrar una solución para un problema, que no vale la pena abrir una nueva pregunta, pero me llevó aquí.

Aquí es un pequeño fragmento de código, que combina lists, zip() y *args, para proporcionar un envoltorio que puede hacer frente a una cantidad desconocida de funciones con una cantidad desconocida de argumentos.

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) 

tener en cuenta, que zip() no proporciona un control de seguridad para las listas de longitud desigual, ver zip iterators asserting for equal length in python.

Cuestiones relacionadas