파이썬에서 ** kwargs를 사용하는 올바른 방법


453

**kwargs파이썬이 기본값에 올 때 사용하는 적절한 방법은 무엇입니까 ?

kwargs사전을 반환하지만 기본값을 설정하는 가장 좋은 방법은 무엇입니까? 사전으로 액세스해야합니까? get 기능을 사용 하시겠습니까?

class ExampleClass:
    def __init__(self, **kwargs):
        self.val = kwargs['val']
        self.val2 = kwargs.get('val2')

간단한 질문이지만 좋은 자료를 찾을 수없는 질문입니다. 사람들은 내가 본 코드에서 다른 방식으로 수행하며 사용 방법을 알기가 어렵습니다.

답변:


468

get()사전에없는 키에 기본값을 전달할 수 있습니다 .

self.val2 = kwargs.get('val2',"default value")

그러나 특정 기본값으로 특정 인수를 사용하려는 경우 먼저 명명 된 인수를 사용하지 않는 이유는 무엇입니까?

def __init__(self, val2="default value", **kwargs):

16
필수 인수에 대해서만 위치 인수를 사용하고 지정되거나 지정되지 않을 수있는 인수에 대해 kwargs를 사용하고 싶지만 기본값을 갖는 것이 도움이됩니다. kwargs는 원하는 순서대로 인수를 제출할 수 있기 때문에 좋습니다. 위치 주장은 그 자유를 제공하지 않습니다.
Kekoa

95
원하는 순서대로 명명 된 인수를 전달할 수 있습니다. kwargs의 경우 이름을 사용하지 않으면 위치를 준수해야합니다. 오히려 kwargs와 반대로 명명 된 인수를 사용하면 이름을 사용하지 않을 수있는 추가적인 자유 를 얻게됩니다 . 그러나 순서를 유지해야합니다.
balpha

13
@Kekoa : 언제든지 원하는 순서대로 명명 된 인수를 제출할 수 있습니다. 이 유연성을 얻기 위해 ** kwargs를 사용할 필요는 없습니다.
S.Lott

13
pylint는 kwargs를 사용하기에 잘못된 형식으로 플래그를 지정합니다 __init__(). 왜 이것이 보풀이없는 범죄인지 설명 할 수 있습니까?
hughdbrown


271

대부분의 답변에서 예를 들어

def f(**kwargs):
    foo = kwargs.pop('foo')
    bar = kwargs.pop('bar')
    ...etc...

와 같다"

def f(foo=None, bar=None, **kwargs):
    ...etc...

이것은 사실이 아닙니다. 후자의 경우 f로 호출 할 수 있지만 f(23, 42)전자의 경우 에는 위치 호출이없는 명명 된 인수 허용 합니다. 발신자에게 최대의 유연성을 허용하려는 경우가 많으므로 대부분의 답변에서 주장하는 것처럼 두 번째 형식이 바람직합니다. 그러나 항상 그런 것은 아닙니다. 일반적으로 몇 개의 매개 변수 만 전달되는 많은 선택적 매개 변수를 허용하는 경우 명명 된 인수를 강제로 사용하는 것이 좋습니다 (예 : 호출 사이트에서 사고 및 읽을 수없는 코드 방지) threading.Thread. 첫 번째 형태는 파이썬 2에서 구현하는 방법입니다.

이 관용구는 파이썬 3에서 특별한 지원 구문을 갖 *습니다. def서명 에서 단일 뒤에 오는 모든 인수 는 키워드 전용입니다. 즉, 위치 인수로 전달 될 수없고 이름이 지정된 인수로만 전달 될 수 있습니다. 따라서 Python 3에서는 위와 같이 코드를 작성할 수 있습니다.

def f(*, foo=None, bar=None, **kwargs):
    ...etc...

실제로 Python 3 에서는 선택 사항 이 아닌 키워드 전용 인수 (기본값 이없는 인수)를 가질 수도 있습니다 .

그러나 Python 2는 여전히 생산적인 수명이 길기 때문에 Python 3에서 언어로 직접 지원되는 중요한 디자인 아이디어를 Python 2에서 구현할 수있는 기술과 관용구를 잊지 않는 것이 좋습니다 !


10
@ Alex Martelli : kwargs가 우수한 인수는 아니지만 명명 된 인수와 동일하다고 주장하는 단일 답변을 찾지 못했습니다. 그러나 Py3k에 대한 좋은 담론은 변하기 때문에 +1
balpha

1
@ Alex Martelli : 귀하의 답변에 감사드립니다. 파이썬 3은 필수 키워드 인수를 허용한다는 사실을 알게되었습니다.
FloW

78

나는 이런 것을 제안한다

def testFunc( **kwargs ):
    options = {
            'option1' : 'default_value1',
            'option2' : 'default_value2',
            'option3' : 'default_value3', }

    options.update(kwargs)
    print options

testFunc( option1='new_value1', option3='new_value3' )
# {'option2': 'default_value2', 'option3': 'new_value3', 'option1': 'new_value1'}

testFunc( option2='new_value2' )
# {'option1': 'default_value1', 'option3': 'default_value3', 'option2': 'new_value2'}

그런 다음 원하는 방식으로 값을 사용하십시오.

dictionaryA.update(dictionaryB)중복 키 dictionaryBdictionaryA덮어 쓰는 내용을 추가합니다 .


2
감사합니다 @AbhinavGupta! 정확히 내가 찾던 것. 방금 추가 한 다음 for key in options: self.__setattr__(key, options[key])에 시작하겠습니다. :)
propjk007

53

당신은 할

self.attribute = kwargs.pop('name', default_value)

또는

self.attribute = kwargs.get('name', default_value)

을 사용 pop하면 가짜 값이 전송되었는지 확인하고 적절한 조치를 취할 수 있습니다 (있는 경우).


2
.pop“스퓨리어스 값이 전송되었는지 확인”하는 데 도움이된다고 제안하여 의미를 명확하게 설명 할 수 있습니까 ?
Alan H.

13
@ Alan H. : 모든 팝핑이 끝난 후 kwargs에 남은 것이 있으면 가짜 값을 얻습니다.
Vinay Sajip

@VinaySajip : 좋아, 그것은 .pop "vs".get에 대한 좋은 점이지만, 호출자가 위치 매개 변수를 사용하지 않도록 강요하는 것 외에도 이름이 지정된 인수보다 pop이 선호되는 이유를 여전히 알지 못합니다.
MestreLion

1
@MestreLion : API에서 허용하는 키워드 인수 수에 따라 다릅니다. 내 제안이 명명 된 인수보다 낫다고 주장하지는 않지만 Python을 사용하면 명명되지 않은 인수를 kwargs이유 를 포착 할 수 있습니다 .
Vinay Sajip

그냥 확인 중입니다. 키가 존재하고 그렇지 않으면 default_value전달 된 키를 반환하면 pop은 사전 값을 반환 합니까? 그리고 그 열쇠를 나중에 제거합니까?
Daniel Möller

42

** kwargs 및 기본값을 사용하는 것은 쉽습니다. 그러나 때때로 ** kwargs를 사용해서는 안됩니다.

이 경우 ** kwargs를 실제로 최대한 활용하지는 않습니다.

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = kwargs.get('val',"default1")
        self.val2 = kwargs.get('val2',"default2")

위의 "왜 귀찮게?" 선언. 와 동일

class ExampleClass( object ):
    def __init__(self, val="default1", val2="default2"):
        self.val = val
        self.val2 = val2

** kwargs를 사용하는 경우 키워드는 선택 사항이 아니라 조건부입니다. 단순한 기본값보다 더 복잡한 규칙이 있습니다.

** kwargs를 사용하는 경우 일반적으로 간단한 기본값이 적용되지 않는 다음과 같은 것을 의미합니다.

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = "default1"
        self.val2 = "default2"
        if "val" in kwargs:
            self.val = kwargs["val"]
            self.val2 = 2*self.val
        elif "val2" in kwargs:
            self.val2 = kwargs["val2"]
            self.val = self.val2 / 2
        else:
            raise TypeError( "must provide val= or val2= parameter values" )

나는 그 작은 두뇌 맛보기를 좋아합니다! 나는 계속 생각했다. "하지만 당신은 get 또는 pop을 사용할 수 있습니다. 그들은 서로 의존적입니다 ..."
trojjer

28

**kwargs인수의 수를 알 수 없을 때 사용 되기 때문에 왜 이것을하지 않습니까?

class Exampleclass(object):
  def __init__(self, **kwargs):
    for k in kwargs.keys():
       if k in [acceptable_keys_list]:
          self.__setattr__(k, kwargs[k])

예, 이것은 우아하고 강력합니다. allowed_keys_list 주위의 대괄호에 대해서는 너무 확실하지 않습니다. 그러나 이것을 튜플 또는 목록으로 만든 다음 "if"문에 괄호를 버리십시오
mike rodent

모든 키가 필요한 경우에 약간 수정했습니다 : stackoverflow.com/questions/1098549/…
rebelliard

14

다른 접근 방식이 있습니다.

def my_func(arg1, arg2, arg3):
    ... so something ...

kwargs = {'arg1': 'Value One', 'arg2': 'Value Two', 'arg3': 'Value Three'}
# Now you can call the function with kwargs like this:

my_func(**kwargs)

Django CBV에서 많이 사용됩니다 (예 :) get_form_kwargs(). ccbv.co.uk/projects/Django/1.5/django.views.generic.edit/…
trojjer

get_form()방법은 get_form_kwargs위에서 언급 한 것처럼 다른 방법을 연기하여 키워드 인수를 광범위하게 얻는 방법을 보여줍니다 . 다음과 같이 양식을 인스턴스화합니다 form_class(**self.get_form_kwargs())..
trojjer

그러면 get_form_kwargs()서브 클래스보기에서 재정의 하고 특정 논리에 따라 크워 그를 추가 / 제거 할 수 있습니다. 그러나 그것은 장고 튜토리얼을위한 것입니다.
trojjer

12

**kwargs파이썬에서 기본값을 사용할 때 올바른 방법 은 setdefault아래 주어진 주어진 dictionary 메소드를 사용하는 것입니다 .

class ExampleClass:
    def __init__(self, **kwargs):
        kwargs.setdefault('val', value1)
        kwargs.setdefault('val2', value2)

이런 방식으로 사용자가 키워드에서 'val'또는 'val2'를 전달하면 args사용됩니다. 그렇지 않으면 설정된 기본값이 사용됩니다.


11

이런 식으로 할 수 있습니다

class ExampleClass:
    def __init__(self, **kwargs):
        arguments = {'val':1, 'val2':2}
        arguments.update(kwargs)
        self.val = arguments['val']
        self.val2 = arguments['val2']

11

setattr 사용 에 대한 @ srhegde 제안 에 후속 :

class ExampleClass(object):
    __acceptable_keys_list = ['foo', 'bar']

    def __init__(self, **kwargs):
        [self.__setattr__(key, kwargs.get(key)) for key in self.__acceptable_keys_list]

이 변형은 클래스가 acceptable목록 에 모든 항목을 가질 것으로 예상 될 때 유용 합니다.


1
이것은 목록 이해의 유스 케이스가 아니며 init 메소드에서 for 루프를 사용해야합니다.
ettanany

5

이것을 * args와 결합하려면 정의의 끝에 * args와 ** kwargs를 유지해야합니다.

그래서:

def method(foo, bar=None, *args, **kwargs):
    do_something_with(foo, bar)
    some_other_function(*args, **kwargs)

1

@AbhinavGupta와 @Steef는을 사용하도록 제안했는데, update()큰 인수 목록을 처리하는 데 매우 도움이되었습니다.

args.update(kwargs)

사용자가 허위 / 지원되지 않는 인수를 전달하지 않았는지 확인하려면 어떻게해야합니까? @VinaySajip pop()은 인수 목록을 반복적으로 처리하는 데 사용할 수 있다고 지적했습니다 . 그런 다음 남은 논쟁은 허위입니다. 좋은.

이 작업을 수행하는 또 다른 방법은 다음과 같이 간단한 구문을 유지합니다 update().

# kwargs = dictionary of user-supplied arguments
# args = dictionary containing default arguments

# Check that user hasn't given spurious arguments
unknown_args = user_args.keys() - default_args.keys()
if unknown_args:
    raise TypeError('Unknown arguments: {}'.format(unknown_args))

# Update args to contain user-supplied arguments
args.update(kwargs)

unknown_argsA는 set디폴트 발생하지 않는 인수의 이름을 포함하는가.


0

알 수 없거나 여러 개의 인수를 처리하기위한 또 다른 간단한 솔루션은 다음과 같습니다.

class ExampleClass(object):

    def __init__(self, x, y, **kwargs):
      self.x = x
      self.y = y
      self.attributes = kwargs

    def SomeFunction(self):
      if 'something' in self.attributes:
        dosomething()

0

** kwargs는 여러 개의 키워드 인수를 자유롭게 추가 할 수 있습니다. 기본 값을 설정할 수있는 키 목록이있을 수 있습니다. 그러나 무한한 키의 기본값을 설정하는 것은 불필요 해 보입니다. 마지막으로 키를 인스턴스 속성으로 사용하는 것이 중요 할 수 있습니다. 따라서 다음과 같이하면됩니다.

class Person(object):
listed_keys = ['name', 'age']

def __init__(self, **kwargs):
    _dict = {}
    # Set default values for listed keys
    for item in self.listed_keys: 
        _dict[item] = 'default'
    # Update the dictionary with all kwargs
    _dict.update(kwargs)

    # Have the keys of kwargs as instance attributes
    self.__dict__.update(_dict)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.