2009-05-03 22 views
126

Ich versuche, eine Funktion innerhalb einer anderen Funktion in Python aufzurufen, kann aber nicht die richtige Syntax finden. Was ich möchte, ist etwas in der Art:Aufruf einer Funktion mit Argumentliste in 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]) 

In diesem Fall funktioniert der erste Anruf, und zweitens nicht. Was ich ändern möchte, ist die Wrapper-Funktion und nicht die aufgerufenen Funktionen.

Antwort

225

Um ein wenig auf den anderen Antworten zu erweitern:

In th e line:

def wrapper(func, *args): 

Der * neben args bedeutet „der Parameter den Rest gegeben und sie in einer args genannt Liste setzen“.

In der Zeile:.

func(*args) 

Der * neben args hier bedeutet „nehmen Sie diese Liste mit dem Namen args und‚auspacken‘es in den Rest der Parameter

So können Sie folgendes tun :

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

in wrapper2 wird die Liste explizit übergeben, aber in beiden Wrapper args enthält die Liste [1,2,3].

+20

Eine Sache, die ich nicht oft erwähnt habe, ist, wie man eine Funktion mit * args aufruft, wenn Sie eine Liste oder ein Tupel haben, die Sie übergeben wollen. Dafür muss man es so nennen: wrapper1 (func2, * mylist) – pug

+0

* args in 'def wrapper (func, * args)' ist 'method (params object [] args)' ist in C#. –

+0

Beachten Sie, dass '* args' das letzte Argument in der Funktionsdefinition sein muss. –

10

Sie können die Syntax * args und ** kwargs für Argumente mit variabler Länge verwenden.

What do *args and **kwargs mean?

Und von der offiziellen Python Tutorial

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

+0

Also brauche ich es, um sowohl * args und ** kwargs zu bekommen und es mit ihnen zu nennen? – SurDin

+1

Nein, Sie können entweder/oder verwenden, aber sie werden oft zusammen gepaart. In Ihrem Fall benötigen Sie nur * Args. – JimB

+0

Ok, es funktioniert, aber es lässt mich immer noch nicht eine Liste von Argumenten passieren, und ich muss sie getrennt weitergeben. Es stört mich nicht sehr, in meiner gegenwärtigen Situation, aber es wäre immer noch gut zu wissen, wie man das macht. (Ich brauche Wrapper (func2, x, y, z) und nicht wrapper (func2, [x, y, z])) – SurDin

8

Sie müssen Auspacken Argumente verwenden ..

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

Die wörtliche Antwort auf Ihre Frage (genau das zu tun, was Sie gefragt, nur die Verpackung zu ändern, nicht die Funktionen oder die Funktionsaufrufe) ist einfach die Zeile zu ändern

func(args) 

func(*args) 
zu lesen

Dies weist Python an, die angegebene Liste (in diesem Fall args) zu übernehmen und den Inhalt als Positionsargumente an die Funktion zu übergeben.

Dieser Trick funktioniert auf beiden „Seiten“ der Funktionsaufruf, so eine Funktion wie folgt definiert:

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

wäre in der Lage, so viele Positions Argumente zu akzeptieren, wie Sie an ihm werfen, und legen Sie sie alle in eine Liste namens args.

Ich hoffe, dass dies hilft, die Dinge ein wenig zu klären. Beachten Sie, dass dies auch mit dicts/keyword-Argumenten möglich ist, indem Sie ** anstelle von * verwenden.

15

Der einfachste Weg, um eine Funktion

func(*args, **kwargs) 

... einzuwickeln ist manuell einen Wrapper zu schreiben, die func() in sich nennen würde:

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

In Funktion ist ein Python Objekt, so dass Sie den Namen als Argument einer anderen Funktion übergeben und zurückgeben können. Sie können auch einen Wrapper-Generator für jede Funktion anyFunc() schreiben:

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

Bitte beachten Sie auch in Python beachten Sie, dass, wenn Sie nicht wissen, oder wollen nicht alle Argumente einer Funktion zu nennen, Sie beziehen sich auf ein Tupel von Argumenten, die mit seinem Namen bezeichnet wird, durch ein Sternchen in Klammern nach dem Funktionsnamen vorangestellt:

*args 

zum Beispiel können Sie eine Funktion definieren, die eine beliebige Anzahl von Argumenten entgegennehmen würde:

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

Python bietet noch weitere Manipulationen an Funktionsargumenten. Sie können einer Funktion erlauben, Schlüsselwortargumente zu übernehmen. Innerhalb des Funktionskörpers werden die Schlüsselwortargumente in einem Wörterbuch gehalten. In den Klammern nach dem Funktionsnamen ist dieser Wörterbuch mit zwei Sternchen, gefolgt vom Namen des Wörterbuchs bezeichnet:

**kwargs 

Ein ähnliches Beispiel, die das Schlüsselwort Argument Wörterbuch druckt:

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

Ein kleiner Zusatz zu vorherige Antworten, da ich keine Lösung für ein Problem finden konnte, das es nicht wert ist, eine neue Frage zu eröffnen, sondern mich hierher geführt hat.

Hier ist ein kleiner Code-Schnipsel, die lists, zip() und *args verbindet, einen Wrapper zu schaffen, die mit einer unbekannten Menge von Funktionen mit einer unbekannten Menge von Argumenten umgehen kann.

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) 

Denken Sie daran, dass zip() nicht eine Sicherheitsprüfung für Listen von ungleicher Länge liefert, siehe zip iterators asserting for equal length in python.

Verwandte Themen