* args 및 ** kwargs가있는 기본 인수


84

에서 파이썬 2.x에서 와 기본 인자를 사용하기에 적합한 방법이다 (I 2.7을 사용), *args그리고 **kwargs?
이 주제와 관련된 SO에 대한 질문을 찾았지만 Python 3 :
* args, ** kwargs 및 선택적 / 기본 인수를 사용하여 Python 함수 호출

거기에서 그들은이 방법이 효과가 있다고 말합니다.

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']
    #...

아직도 내가 걸쳐 실행 중에 가장 간결한 설명 : saltycrane.com/blog/2008/01/...
verbsintransit

4
명시 적으로 호출 하지 마십시오__contains__ . 항상 사용 in: 'opt_arg' in kwargs. (더 나은 : kwargs.get('opt_arg', 'def_val')mgilson의 답변에서와 같이).
nneonneo 2013 년

답변:


80

기본 인수를 다음 앞에 넣으십시오 *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에서도 작동합니다. Python 3에서 기본 인수를 뒤에 넣으면 위치가 아닌 이름으로 지정할 *args수있는 "키워드 전용"인수가 됩니다. Python 2에서 키워드 전용 인수를 원하는 경우 @mgilson의 솔루션을 사용할 수 있습니다.


1
예, 그 이유는 *args. 키워드 전용 인수를 원한다면 올바른 방법입니다.
nneonneo 2013 년

위의 의견에서 답을 얻었습니다. (다른 b로 함수를 호출하고 * args도 추가하려면 어떻게해야합니까?)

어쨌든 묻기 전에이 솔루션을 시도했지만 opt_arg를 정의한 후에 kwargs 만 사용하는 경우에만 작동하는 것도 발견했습니다.

@nneonneo : 예제를 얻었지만이 방법은 링크에 설명 된대로 Python 3.x에서 허용하는 것처럼 기본 인수와 * args를 동시에 지정할 수있는 자유를 제공하지 않습니다. 그래?

5
*args, no를 채우는 동안 기본 인수를 그대로 둘 수 없습니다. 이 기능이 Python 3에 추가 된 이유입니다. 일반적으로 Python 2의 기본 인수는 0과 같이 분명한 것으로 지정되거나 None명시 적으로 전달 될 수 있습니다.
nneonneo

55

다른 질문의 구문은 python3.x 전용이며 키워드 전용 인수를 지정합니다. python2.x에서는 작동하지 않습니다.

python2.x pop의 경우 kwargs에서 다음과 같이 처리합니다.

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

또한 기본 인수 앞에 * args를 지정합니다.

4

다음과 같은 데코레이터를 사용할 수도 있습니다.

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

1

더 일반적이고 더 간결하게 만들려고 노력하면서 솔루션 접근 방식에 아주 가깝게 고수하면서 다음과 같은 것을 고려하는 것이 좋습니다.

>>> 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'})

0

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의 답변과 달리 기본 호출에 임의의 전달을 처리합니다 .


1
이것은 즉, 유효한 코드를 사용하는 경우 명확 것 'opt_arg'대신 < kwarg-name >하고 'def_val'대신< kwarg-name-default-value >
wjandrea

0

이 답변은 Daniel Américo가 제안한 내용의 확장입니다 .

이 데코레이터는 엄격하게 정의 되지 않은 경우 기본 kwarg 값을 할당합니다 .

from functools import wraps

def force_kwargs(**defaultKwargs):
    def decorator(f):
        @wraps(f)
        def g(*args, **kwargs):
            new_args = {}
            new_kwargs = defaultKwargs
            varnames = f.__code__.co_varnames
            new_kwargs.update(kwargs)
            for k, v in defaultKwargs.items():
                if k in varnames:
                    i = varnames.index(k)
                    new_args[(i, k)] = new_kwargs.pop(k)
            # Insert new_args into the correct position of the args.
            full_args = list(args)
            for i, k in sorted(new_args.keys()):
                if i <= len(full_args):
                    full_args.insert(i, new_args.pop((i, k)))
                else:
                    break
            # re-insert the value as a key-value pair
            for (i, k), val in new_args.items():
                new_kwargs[k] = val
            return f(*tuple(full_args), **new_kwargs)
        return g
    return decorator

결과

@force_kwargs(c=7)
def f(a, b='B', c='C', d='D', *args, **kw):
    return a, b, c, d, args, kw
#                               a    b  c    d  args      kwargs
f('r')                      # 'r', 'B', 7, 'D',   (),         {}
f(1,2,3)                    #   1,   2, 7,   3,   (),         {}
f(1, 2, 3, b=3, c=9, f='F') #   1,   3, 9,   2, (3,), {'f': 'F'}

다른

함수 정의에 작성된 기본값을 사용하려면 기본값 f.func_defaults을 나열 하는를 사용하여 인수 기본값에 액세스 할 수 있습니다 . 당신은해야 할 것 zip의 말에 그 f.__code__.varnames변수의 이름이 기본 값과 일치하도록.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.