Вызов функции со списком аргументов в Python - PullRequest
139 голосов
/ 03 мая 2009

Я пытаюсь вызвать функцию внутри другой функции в 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])

В этом случае первый вызов будет работать, а второй - нет. Я хочу изменить функцию-обертку, а не вызываемые функции.

Ответы [ 6 ]

253 голосов
/ 03 мая 2009

Чтобы немного расширить другие ответы:

В строке:

def wrapper(func, *args):

* Рядом с args означает «взять остальные заданные параметры и поместить их в список с именем args».

В строке:

    func(*args)

Здесь * рядом с args означает «взять этот список, называемый args, и« развернуть »его в остальные параметры.

Таким образом, вы можете сделать следующее:

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

В wrapper2 список передается явно, но в обеих оболочках args содержит список [1,2,3].

18 голосов
/ 04 мая 2009

Самый простой способ обернуть функцию

    func(*args, **kwargs)

... - это вручную написать оболочку, которая будет вызывать func () внутри себя:

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

В Python функция является объектом, поэтому вы можете передать ее имя в качестве аргумента другой функции и вернуть его. Вы также можете написать генератор обёрток для любой функции anyFunc () :

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

Обратите также внимание, что в Python, когда вы не знаете или не хотите называть все аргументы функции, вы можете ссылаться на кортеж аргументов, который обозначается его именем, которому предшествует звездочка в скобки после имени функции:

    *args

Например, вы можете определить функцию, которая будет принимать любое количество аргументов:

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

Python обеспечивает дальнейшие манипуляции с аргументами функции. Вы можете разрешить функции принимать ключевые аргументы. Внутри тела функции ключевые аргументы хранятся в словаре. В скобках после имени функции этот словарь обозначается двумя звездочками, за которыми следует название словаря:

    **kwargs

Аналогичный пример, который печатает словарь аргументов ключевого слова:

    def testFunc(**kwargs):
        print kwargs    # prints the dictionary of keyword arguments
10 голосов
/ 03 мая 2009

Вы можете использовать синтаксис * args и ** kwargs для аргументов переменной длины.

Что означают * args и ** kwargs?

И из официального учебника по питону

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

9 голосов
/ 03 мая 2009

Дословный ответ на ваш вопрос (чтобы сделать именно то, что вы просили, изменив только оболочку, а не функции или вызовы функций), просто измените строку

func(args)

читать

func(*args)

Это говорит Python, что нужно взять заданный список (в данном случае args) и передать его содержимое функции в качестве позиционных аргументов.

Этот трюк работает с обеих сторон вызова функции, поэтому функция определяется следующим образом:

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

сможет принять столько позиционных аргументов, сколько вы набросите, и поместить их всех в список с именем args.

Надеюсь, это поможет немного прояснить ситуацию. Обратите внимание, что это все возможно и с аргументами dicts / keyword, используя ** вместо *.

8 голосов
/ 03 мая 2009

Вам нужно использовать аргументы для распаковки ..

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)
0 голосов
/ 21 апреля 2017

Небольшое дополнение к предыдущим ответам, поскольку я не смог найти решение проблемы, которая не стоит открывать новый вопрос, но привела меня сюда.

Вот небольшой фрагмент кода, который объединяет lists, zip() и *args, чтобы предоставить оболочку, которая может работать с неизвестным количеством функций с неизвестным количеством аргументов.

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)

Имейте в виду, что zip() не обеспечивает проверку безопасности для списков неравной длины, см. zip-итераторы, утверждающие равную длину в python .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...