Аргументы по умолчанию с *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, это приводит к SyntaxError
. Есть ли рекомендуемый способ определить такой функции?
Я получил это работает, но я думаю, что есть лучше решение.
def func(arg1, arg2, *args, **kwargs):
opt_arg ='def_val'
if kwargs.__contains__('opt_arg'):
opt_arg = kwargs['opt_arg']
#...
5 ответов:
просто поставьте аргументы по умолчанию перед
*args
:def foo(a, b=3, *args, **kwargs):
теперь
b
будет явно установлен, если вы передадите его в качестве ключевого аргумента или второго позиционного аргумента.примеры:
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. Ставим по умолчанию arg после
*args
в Python 3 делает его a "ключевое слово-только" аргумент, который может только указывается по имени, а не по должности. Если вам нужен аргумент только для ключевых слов в Python 2, Вы можете использовать решение @mgilson.
синтаксис в другом вопросе-python3.только x и задает аргументы только для ключевых слов. Это не работает на python2.x.
для python2.х, я бы
pop
это из kwargs:def func(arg1, arg2, *args, **kwargs): opt_arg = kwargs.pop('opt_arg', 'def_val')
еще один способ справиться с 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.
придерживаясь довольно близко к вашему подходу к решению, пытаясь сделать его более общим и более компактным, я бы предложил рассмотреть что-то вроде этого:
>>> 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'})
вы также можете использовать декоратор такой:
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