Wywołanie funkcji z listą argumentów w Pythonie

Próbuję wywołać funkcję wewnątrz innej funkcji w Pythonie, ale nie mogę znaleźć właściwej składni. To co chcę zrobić to coś takiego:

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

W tym przypadku pierwsze połączenie zadziała, a drugie nie. Chcę zmodyfikować funkcję wrappera, a nie wywołane funkcje.

Author: SilentGhost, 2009-05-03

6 answers

Aby rozwinąć trochę inne odpowiedzi:

W linii:

def wrapper(func, *args):

* obok args oznacza " weź resztę podanych parametrów i umieść je na liście o nazwie args".

W linii:

    func(*args)

* obok args tutaj oznacza "weź tę listę nazwaną args i 'rozpakuj' ją do reszty parametrów.

Więc możesz wykonać następujące czynności:

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

W wrapper2 lista jest przekazywana jawnie, ale w obu opakowaniach args zawiera listę [1,2,3].

 235
Author: itsadok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-03 15:17:44

Najprostszy sposób zawijania funkcji

    func(*args, **kwargs)

... jest ręczne napisanie wrappera wywołującego func () wewnątrz siebie:

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

W Pythonie funkcja jest obiektem, więc możesz przekazać jej nazwę jako argument innej funkcji i zwrócić ją. Możesz również napisać generator wrappera dla dowolnej funkcji anyFunc():

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

Należy również pamiętać, że w Pythonie, gdy nie znasz lub nie chcesz wymienić wszystkich argumentów funkcji, możesz odwołać się do krotka argumentów oznaczana nazwą, poprzedzona gwiazdką w nawiasach po nazwie funkcji:

    *args

Na przykład można zdefiniować funkcję, która przyjmowałaby dowolną liczbę argumentów:

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

Python umożliwia jeszcze dalszą manipulację argumentami funkcji. Możesz zezwolić funkcji na przyjmowanie argumentów słów kluczowych. W ciele funkcji argumenty słów kluczowych są przechowywane w słowniku. W nawiasach po nazwie funkcji słownik ten jest oznaczony po dwóch gwiazdkach, po których następuje Nazwa słownika:

    **kwargs

Podobny przykład wypisujący słowo kluczowe arguments dictionary:

    def testFunc(**kwargs):
        print kwargs    # prints the dictionary of keyword arguments
 16
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-24 15:18:15

Możesz używać składni *args i **kwargs dla argumentów o zmiennej długości.

Co oznaczają "args" i "kwargs"?

I z oficjalnego samouczka Pythona

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

 10
Author: JimB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:41

Musisz użyć argumentów rozpakowujących..

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
Author: Joril,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-03 13:53:57

Dosłowna odpowiedź na twoje pytanie (aby zrobić dokładnie to, o co prosiłeś, zmieniając tylko wrapper, a nie funkcje lub wywołania funkcji) to po prostu zmienić linię

func(args)

Do przeczytania

func(*args)

To mówi Pythonowi, aby wziął podaną listę (w tym przypadku args) i przekazał jej zawartość funkcji jako argumenty pozycyjne.

Ten trik działa po obu "stronach" wywołania funkcji, więc funkcja zdefiniowana tak:

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

Byłby w stanie przyjąć jak najwięcej argumenty pozycyjne, gdy je rzucasz, i umieść je wszystkie na liście o nazwie args.

Mam nadzieję, że to trochę wyjaśni. Zauważ, że wszystko to jest możliwe również z argumentami dicts/keyword, używając ** zamiast *.
 8
Author: Alan Rowarth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-03 19:48:20

Mały dodatek do poprzednich odpowiedzi, ponieważ nie mogłem znaleźć rozwiązania problemu, co nie jest warte otwierania nowego pytania, ale doprowadziło mnie tutaj.

Oto mały fragment kodu, który łączy lists, zip() i *args, aby zapewnić wrapper, który może radzić sobie z nieznaną ilością funkcji z nieznaną ilością argumentów.

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)

Należy pamiętać, że zip() nie zapewnia kontroli bezpieczeństwa dla list o nierównej długości, patrz Iteratory zip twierdzące o równej długości w python .

 0
Author: P. Siehr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:08