Аргументы по умолчанию с * 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']
#...
Ответы
Ответ 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.