Default arguments with *args and **kwargs
In Python 2.x (I use 2.7), which is the proper way to use default arguments with *args and **kwargs?
I've found a question on SO related to this topic, but that is for Python 3:
Calling a Python function with *args,**kwargs and optional / default arguments
There, they say this method works:
def func(arg1, arg2, *args, opt_arg='def_val', **kwargs):
#...
In 2.7, it results in a SyntaxError. Is there any recommended way to define such a function?
I got it working this way, but I'd guess there is a nicer solution.
def func(arg1, arg2, *args, **kwargs):
opt_arg ='def_val'
if kwargs.__contains__('opt_arg'):
opt_arg = kwargs['opt_arg']
#...
Just put the default arguments before the *args:
def foo(a, b=3, *args, **kwargs):
Now, b will be explicitly set if you pass it as a keyword argument or the second positional argument.
Examples:
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}
Note that, in particular, foo(x, y, b=z) doesn't work because b is assigned by position in that case.
This code works in Python 3 too. Putting the default arg after *args in Python 3 makes it a "keyword-only" argument that can only be specified by name, not by position. If you want a keyword-only argument in Python 2, you can use @mgilson's solution.
The syntax in the other question is python3.x only and specifies keyword only arguments. It doesn't work on python2.x.
For python2.x, I would pop it out of kwargs:
def func(arg1, arg2, *args, **kwargs):
opt_arg = kwargs.pop('opt_arg', 'def_val')
You could also use a decorator like this:
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
Then just do:
@default_kwargs(defaultVar1 = defaultValue 1, ...)
def foo(*args, **kwargs):
# Anything in here
For instance:
@default_kwargs(a=1)
def f(*args, **kwargs):
print(kwargs['a']+ 1)
f() # Returns 2
f(3) # Returns 4
Sticking quite close to your solution approach while trying to make it more generic and more compact I would suggest to consider something like this:
>>> 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'})
Another way to handle with 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)
This handles passing arbitrary *args to the underlying call unlike @nneonneo's answer.
참고URL : https://stackoverflow.com/questions/15301999/default-arguments-with-args-and-kwargs
'Program Club' 카테고리의 다른 글
| How can I deal with HTTP GET query string length limitations and still want to be RESTful? (0) | 2020.10.21 |
|---|---|
| Jasmine vs. Mocha JavaScript testing for Rails 3.1+ (0) | 2020.10.21 |
| How to access Session variables and set them in javascript? (0) | 2020.10.21 |
| fatal: 'origin' does not appear to be a git repository (0) | 2020.10.21 |
| Why does ?: cause a conversion error while if-else does not? (0) | 2020.10.21 |