Подтвердить что ты не робот

Аргументы по умолчанию с * args и ** kwargs

В Python 2.x (я использую 2.7), что является правильным способом использования аргументов по умолчанию с *args и **kwargs?
Я нашел вопрос о SO, относящийся к этой теме, но это для Python 3:
Вызов функции Python с * args, ** kwargs и необязательными/аргументами по умолчанию

Там, говорят, этот метод работает:

def func(arg1, arg2, *args, opt_arg='def_val', **kwargs):
    #...

В 2.7 это приводит к a SyntaxError. Есть ли рекомендуемый способ определения такой функции?
Я работал над этим так, но я думаю, что есть более приятное решение.

def func(arg1, arg2, *args, **kwargs):
    opt_arg ='def_val'
    if kwargs.__contains__('opt_arg'):
        opt_arg = kwargs['opt_arg']
    #...
4b9b3361

Ответ 1

Просто поставьте аргументы по умолчанию перед *args:

def foo(a, b=3, *args, **kwargs):

Теперь b будет явно задан, если вы передадите его как аргумент ключевого слова или второй аргумент positional.

Примеры:

foo(x) # a=x, b=3, args=(), kwargs={}
foo(x, y) # a=x, b=y, args=(), kwargs={}
foo(x, b=y) # a=x, b=y, args=(), kwargs={}
foo(x, y, z, k) # a=x, b=y, args=(z, k), kwargs={}
foo(x, c=y, d=k) # a=x, b=3, args=(), kwargs={'c': y, 'd': k}
foo(x, c=y, b=z, d=k) # a=x, b=z, args=(), kwargs={'c': y, 'd': k}

Обратите внимание, что, в частности, foo(x, y, b=z) не работает, потому что b назначается положением в этом случае.


Этот код работает и в Python 3. Помещение аргумента по умолчанию после *args в Python 3 делает его аргументом "только для ключевого слова", который может быть указан только по имени, а не по положению. Если вы хотите использовать только аргумент ключевого слова в Python 2, вы можете использовать решение @mgilson.

Ответ 2

Синтаксис в другом вопросе - только python3.x и указывает только аргументы ключевого слова. Это не работает на python2.x.

Для python2.x я бы pop из kwargs:

def func(arg1, arg2, *args, **kwargs):
    opt_arg = kwargs.pop('opt_arg', 'def_val')

Ответ 3

Вы также можете использовать декоратор, как это:

import functools
def default_kwargs(**defaultKwargs):
    def actual_decorator(fn):
        @functools.wraps(fn)
        def g(*args, **kwargs):
            defaultKwargs.update(kwargs)
            return fn(*args, **defaultKwargs)
        return g
    return actual_decorator

Тогда просто сделайте:

@default_kwargs(defaultVar1 = defaultValue 1, ...)
def foo(*args, **kwargs):
    # Anything in here

Например:

@default_kwargs(a=1)
def f(*args, **kwargs):
    print(kwargs['a']+ 1)

f() # Returns 2
f(3) # Returns 4

Ответ 4

Придерживаясь довольно близкого подхода к вашему решению, пытаясь сделать его более общим и компактным, я бы посоветовал рассмотреть что-то вроде этого:

>>> def func(arg1, arg2, *args, **kwargs):
...     kwargs_with_defaults = dict({'opt_arg': 'def_val', 'opt_arg2': 'default2'}, **kwargs)
...     #...
...     return arg1, arg2, args, kwargs_with_defaults

>>> func('a1', 'a2', 'a3', 'a5', x='foo', y='bar')
('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'def_val', 'y': 'bar', 'x': 'foo'})

>>> func('a1', 'a2', 'a3', 'a5', opt_arg='explicit_value', x='foo', y='bar')
('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'explicit_value', 'y': 'bar', 'x': 'foo'})

Ответ 5

Еще один способ работы с Python 2.x:

def foo(*args, **kwargs):
    if 'kwarg-name' not in kwargs.keys():
        kwargs['kwarg-name'] = 'kwarg-name-default-value'
    return bar(*args, **kwargs)

Это обрабатывает передачу произвольных *args в базовый вызов в отличие от ответа @nneonneo.