program story

파이썬에서 ** kwargs를 사용하는 이유는 무엇입니까?

inputbox 2020. 11. 23. 08:05
반응형

파이썬에서 ** kwargs를 사용하는 이유는 무엇입니까? 명명 된 인수를 사용하는 것보다 실질적인 이점은 무엇입니까?


나는 정적 언어의 배경에서 왔습니다. 누군가 명명 된 인수에 비해 ** kwargs를 사용할 때의 실제 이점을 설명 할 수 있습니까 (이상적으로는 예제를 통해) ?

나에게 그것은 단지 함수 호출을 더 모호하게 만드는 것 같습니다. 감사.


실제 사례 :

데코레이터-일반적으로 일반적이므로 인수를 미리 지정할 수 없습니다.

def decorator(old):
    def new(*args, **kwargs):
        # ...
        return old(*args, **kwargs)
    return new

알 수없는 수의 키워드 인수로 마술을하고 싶은 곳. Django의 ORM은이를 수행합니다. 예 :

Model.objects.filter(foo__lt = 4, bar__iexact = 'bar')

일련의 이유로 거의 임의의 명명 된 인수를 받아들이고 싶을 수 있습니다. 이것이 **kw양식에서 할 수있는 것입니다.

가장 일반적인 이유는 래핑하는 다른 함수에 바로 인수를 전달하는 것입니다 (데코레이터는 이것의 한 경우이지만 유일한 경우는 먼!)-이 경우 **kw래퍼와 래피 간의 결합을 느슨하게합니다. 랩퍼는 랩 피의 모든 인수를 알거나 신경 쓸 필요가 없습니다. 완전히 다른 또 다른 이유가 있습니다.

d = dict(a=1, b=2, c=3, d=4)

모든 이름을 미리 알려야한다면 분명히이 접근 방식은 존재할 수 없었습니다. 그리고 btw, 해당되는 경우 키가 리터럴 문자열 인 dict를 만드는 방법을 다음과 같이 선호합니다.

d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

후자는 문장 부호가 많고 가독성이 떨어지기 때문입니다.

수락하는 훌륭한 이유가 **kwargs적용되지 않는 경우 수락하지 마십시오. 그렇게 간단합니다. IOW, 호출자가 임의의 이름으로 추가 명명 된 인수를 전달하도록 허용 할 합당한 이유가없는 경우, 그런 일이 발생하지 않도록 **kw하십시오 def. 명령문 의 함수 서명 끝에 양식을 넣지 마십시오 .

에 관해서는 사용하여 **kw 호출에, 그건 당신이 함께 당신이 다음 독립적으로 단일 통화 점의하는 딕셔너리에 해당하는 값으로, 각각을 통과 단일 호출 시점에서 딕셔너리를 사용해야합니다 명명 된 인수의 정확한 세트를 넣을 수 있습니다. 비교:

if x: kw['x'] = x
if y: kw['y'] = y
f(**kw)

에:

if x:
  if y:
    f(x=x, y=y)
  else:
    f(x=x)
else:
  if y:
    f(y=y)
  else:
    f()

두 가지 가능성 (그리고 가장 단순한 종류!)에도 불구 **kw하고, 두 번째 옵션은 절대적으로 견딜 수없고 참을 수 없게 만드는 것이 부족 합니다. 가능성이 6 개일 때, 아마도 약간 더 풍부한 상호 작용에서 어떻게 진행되는지 상상해보십시오. .없이 **kw, 삶은 그러한 상황에서 절대 지옥이 될 것입니다!


**kwargs(및 *args) 사용하려는 또 다른 이유 는 하위 클래스의 기존 메서드를 확장하는 경우입니다. 기존의 모든 인수를 수퍼 클래스의 메서드에 전달하고 싶지만 향후 버전에서 서명이 변경 되더라도 클래스가 계속 작동하도록하고 싶습니다.

class MySubclass(Superclass):
    def __init__(self, *args, **kwargs):
        self.myvalue = kwargs.pop('myvalue', None)
        super(MySubclass, self).__init__(*args, **kwargs)

두 가지 일반적인 경우가 있습니다.

첫째 : 여러 키워드 인자를받는 또 다른 함수를 래핑하고 있지만, 그냥 전달할 것입니다.

def my_wrapper(a, b, **kwargs):
    do_something_first(a, b)
    the_real_function(**kwargs)

둘째 : 객체에 속성을 설정하는 등의 키워드 인수를 기꺼이 허용합니다.

class OpenEndedObject:
    def __init__(self, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

foo = OpenEndedObject(a=1, foo='bar')
assert foo.a == 1
assert foo.foo == 'bar'

**kwargs매개 변수의 이름을 미리 모르면 좋습니다. 예를 들어 dict생성자는이를 사용하여 새 사전의 키를 초기화합니다.

dict(**kwargs) -> new dictionary initialized with the name=value pairs
    in the keyword argument list.  For example:  dict(one=1, two=2)
In [3]: dict(one=1, two=2)
Out[3]: {'one': 1, 'two': 2}

다음은 CGI Python에서 사용한 예입니다. 함수 **kwargs를 사용 하는 클래스를 만들었습니다 __init__. 이를 통해 서버 측에서 클래스를 사용하여 DOM을 에뮬레이션 할 수있었습니다.

document = Document()
document.add_stylesheet('style.css')
document.append(Div(H1('Imagist\'s Page Title'), id = 'header'))
document.append(Div(id='body'))

유일한 문제는 classPython 키워드 이기 때문에 다음을 수행 할 수 없다는 것 입니다.

Div(class = 'foo')

해결책은 기본 사전에 액세스하는 것입니다.

Div(**{'class':'foo'})

이것이 기능의 "올바른"사용법이라고 말하는 것이 아닙니다. 제가 말하는 것은 이와 같은 기능을 사용할 수있는 모든 종류의 예상치 못한 방법이 있다는 것입니다.


또 다른 전형적인 예가 있습니다.

MESSAGE = "Lo and behold! A message {message!r} came from {object_} with data {data!r}."

def proclaim(object_, message, data):
    print(MESSAGE.format(**locals()))

One example is implementing python-argument-binders, used like this:

>>> from functools import partial
>>> def f(a, b):
...     return a+b
>>> p = partial(f, 1, 2)
>>> p()
3
>>> p2 = partial(f, 1)
>>> p2(7)
8

This is from the functools.partial python docs: partial is 'relatively equivalent' to this impl:

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

참고URL : https://stackoverflow.com/questions/1415812/why-use-kwargs-in-python-what-are-some-real-world-advantages-over-using-named

반응형