[python] Python에서 매개 변수의 강제 이름 지정

Python에서는 함수 정의가있을 수 있습니다.

def info(object, spacing=10, collapse=1)

다음 방법 중 하나로 호출 할 수 있습니다.

info(odbchelper)                    
info(odbchelper, 12)                
info(odbchelper, collapse=0)        
info(spacing=15, object=odbchelper)

파이썬이 이름이 지정되어있는 한 임의의 순서 인수를 허용했기 때문입니다.

우리가 겪고있는 문제는 더 큰 함수 중 일부가 커짐에 따라 사람들이 spacing와 사이에 매개 변수를 추가 collapse할 수 있다는 것입니다. 즉, 이름이 지정되지 않은 매개 변수에 잘못된 값이 전달 될 수 있습니다. 또한 때때로 무엇이 들어가야하는지 항상 명확하지 않은 경우도 있습니다. 우리는 사람들이 특정 매개 변수의 이름을 지정하도록 강제하는 방법을 찾고 있습니다. 코딩 표준이 아니라 이상적으로는 플래그 또는 pydev 플러그인입니까?

위의 4 가지 예에서 모든 매개 변수의 이름이 지정되므로 마지막 사람 만 검사를 통과합니다.

확률은 우리가 특정 기능에 대해서만 활성화 할 것이지만이를 구현하는 방법에 대한 제안 또는 가능하다면 감사하겠습니다.



답변

Python 3-예, *인수 목록에서 지정할 수 있습니다 .

에서 문서 :

“*”또는 “* identifier”뒤의 매개 변수는 키워드 전용 매개 변수이며 사용 된 키워드 인수로만 전달 될 수 있습니다.

>>> def foo(pos, *, forcenamed):
...   print(pos, forcenamed)
... 
>>> foo(pos=10, forcenamed=20)
10 20
>>> foo(10, forcenamed=20)
10 20
>>> foo(10, 20)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 1 positional argument (2 given)

다음과 함께 사용할 수도 있습니다 **kwargs.

def foo(pos, *, forcenamed, **kwargs):


답변

다음과 같은 방법으로 함수를 정의하여 사람들이 Python3에서 키워드 인수를 사용하도록 할 수 있습니다.

def foo(*, arg0="default0", arg1="default1", arg2="default2"):
    pass

첫 번째 인수를 이름이없는 위치 인수로 만들면 함수를 호출하는 모든 사람이 내가 요청한 키워드 인수를 사용하도록 강요합니다. Python2에서이를 수행하는 유일한 방법은 다음과 같은 함수를 정의하는 것입니다.

def foo(**kwargs):
    pass

그러면 호출자가 kwargs를 사용하도록 강요하지만 필요한 인수 만 수락하도록 확인을해야하는만큼 좋은 해결책은 아닙니다.


답변

사실, 대부분의 프로그래밍 언어 는 매개 변수 순서를 함수 호출 계약의 일부로 만들지 만 그럴 필요 는 없습니다 . 왜 그럴까요? 질문에 대한 나의 이해는 파이썬이 이와 관련하여 다른 프로그래밍 언어와 다른지 여부입니다. Python 2에 대한 다른 좋은 답변 외에도 다음을 고려하십시오.

__named_only_start = object()

def info(param1,param2,param3,_p=__named_only_start,spacing=10,collapse=1):
    if _p is not __named_only_start:
        raise TypeError("info() takes at most 3 positional arguments")
    return str(param1+param2+param3) +"-"+ str(spacing) +"-"+ str(collapse)

호출자가 인수를 제공 spacing하고 collapse위치 (예외없이) 를 제공 할 수있는 유일한 방법은 다음 과 같습니다.

info(arg1, arg2, arg3, module.__named_only_start, 11, 2)

이미 다른 모듈에 속하는 private 요소를 사용하지 않는 규칙은 Python에서 매우 기본적입니다. Python 자체와 마찬가지로 매개 변수에 대한이 규칙은 부분적으로 만 적용됩니다.

그렇지 않으면 호출은 다음과 같은 형식이어야합니다.

info(arg1, arg2, arg3, spacing=11, collapse=2)

통화

info(arg1, arg2, arg3, 11, 2)

매개 변수에 값 11을 할당 _p하고 함수의 첫 번째 명령에 의해 발생하는 예외 를 지정합니다 .

형질:

  • 앞의 매개 변수 _p=__named_only_start는 위치 (또는 이름)로 허용됩니다.
  • 이후의 매개 변수 _p=__named_only_start는 이름으로 만 제공되어야합니다 (특수 감시 개체에 대한 지식을 __named_only_start얻고 사용 하지 않는 경우 ).

장점 :

  • 매개 변수는 숫자와 의미에서 명시 적입니다 (물론 좋은 이름도 선택되면 나중에).
  • 센티넬이 첫 번째 매개 변수로 지정되면 모든 인수를 이름으로 지정해야합니다.
  • 함수를 호출 할 때 __named_only_start해당 위치에서 센티넬 객체 를 사용하여 위치 모드로 전환 할 수 있습니다 .
  • 다른 대안보다 더 나은 성능을 기대할 수 있습니다.

단점 :

  • 검사는 컴파일 타임이 아닌 런타임 중에 발생합니다.
  • 추가 매개 변수 (인수가 아님) 및 추가 검사 사용. 일반 기능에 비해 약간의 성능 저하.
  • 기능은 언어의 직접적인 지원이없는 해킹입니다 (아래 참고 참조).
  • 함수를 호출 할 때 __named_only_start올바른 위치에있는 센티넬 객체 를 사용하여 위치 모드로 전환 할 수 있습니다 . 예, 이것은 또한 프로로 볼 수 있습니다.

이 답변은 Python 2에서만 유효하다는 점을 명심하십시오. Python 3은 다른 답변에서 설명한 유사하지만 매우 우아하고 언어 지원 메커니즘을 구현합니다.

나는 마음을 열고 그것에 대해 생각할 때 어떤 질문이나 다른 사람의 결정이 어리 석고 멍청하거나 어리석은 것처럼 보이지 않는다는 것을 발견했습니다. 오히려 오히려 나는 일반적으로 많은 것을 배웁니다.


답변

“자연스럽게”발생하지 않는 기본값으로 “가짜”첫 번째 키워드 인수를 만들어 Python 2와 Python 3에서 모두 작동 하는 방식으로 이를 수행 할 수 있습니다 . 해당 키워드 인수 앞에 값이없는 하나 이상의 인수가 올 수 있습니다.

_dummy = object()

def info(object, _kw=_dummy, spacing=10, collapse=1):
    if _kw is not _dummy:
        raise TypeError("info() takes 1 positional argument but at least 2 were given")

이렇게하면 다음이 가능합니다.

info(odbchelper)
info(odbchelper, collapse=0)
info(spacing=15, object=odbchelper)

하지만:

info(odbchelper, 12)                

기능을 다음과 같이 변경하는 경우 :

def info(_kw=_dummy, spacing=10, collapse=1):

모든 인수에는 키워드가 있어야하며 info(odbchelper)더 이상 작동하지 않습니다.

이렇게하면 _kw마지막 항목 뒤에 추가 키워드 인수를 배치 하지 않고도, 뒤에 추가 키워드 인수를 배치 할 수 있습니다 . 예를 들어 논리적으로 그룹화하거나 키워드를 알파벳순으로 정렬하면 유지 관리 및 개발에 도움이 될 수 있습니다.

따라서 def(**kwargs)스마트 편집기에서 서명 정보 를 사용 하고 잃어 버릴 필요가 없습니다 . 당신의 사회적 계약은 (일부) 키워드를 요구함으로써 특정 정보를 제공하는 것입니다. 키워드가 제시된 순서는 무의미 해졌습니다.


답변

최신 정보:

사용 **kwargs하면 문제가 해결되지 않는다는 것을 깨달았습니다 . 프로그래머가 원하는대로 함수 인수를 변경하면 예를 들어 함수를 다음과 같이 변경할 수 있습니다.

def info(foo, **kwargs):

이전 코드는 다시 깨질 것입니다 (이제 모든 함수 호출에는 첫 번째 인수가 포함되어야하기 때문입니다).

그것은 정말로 Bryan이 말한 것에 달려 있습니다.


(…) 사람들이 spacingcollapse(…) 사이에 매개 변수를 추가 할 수 있습니다.

일반적으로 함수를 변경할 때 새 인수는 항상 끝에 있어야합니다. 그렇지 않으면 코드가 깨집니다. 분명해야합니다.
누군가 코드가 깨지도록 함수를 변경하면이 변경은 거부되어야합니다.
(브라이언이 말했듯이 계약과 같습니다)

(…) 때때로 들어가야 할 것이 무엇인지가 항상 명확하지 않습니다.

함수 (즉 def info(object, spacing=10, collapse=1)) 의 시그니처를 보면 기본값 이 없는 모든 인수 가 필수라는 것을 즉시 알 수 있습니다.
무엇 인수가입니다, 문서화 문자열로 가야한다.


이전 답변 (완전성을 위해 유지) :


이것은 아마도 좋은 해결책이 아닐 것입니다.

다음과 같이 함수를 정의 할 수 있습니다.

def info(**kwargs):
    ''' Some docstring here describing possible and mandatory arguments. '''
    spacing = kwargs.get('spacing', 15)
    obj = kwargs.get('object', None)
    if not obj:
       raise ValueError('object is needed')

kwargs키워드 인수를 포함하는 사전입니다. 필수 인수가 있는지 여부를 확인하고 그렇지 않은 경우 예외를 발생시킬 수 있습니다.

단점은 어떤 인수가 가능한지 더 이상 명확하지 않을 수도 있지만 적절한 독 스트링을 사용하면 괜찮을 것입니다.


답변

python3 키워드 전용 인수 ( *)는 다음을 사용하여 python2.x에서 시뮬레이션 할 수 있습니다.**kwargs

다음 python3 코드를 고려하십시오.

def f(pos_arg, *, no_default, has_default='default'):
    print(pos_arg, no_default, has_default)

및 그 동작 :

>>> f(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 3 were given
>>> f(1, no_default='hi')
1 hi default
>>> f(1, no_default='hi', has_default='hello')
1 hi hello
>>> f(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() missing 1 required keyword-only argument: 'no_default'
>>> f(1, no_default=1, wat='wat')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() got an unexpected keyword argument 'wat'

이것은 내가 전환의 자유를 촬영했습니다 참고, 다음을 사용하여 시뮬레이션 할 수 있습니다 TypeErrorKeyError은 “이름 필수 인수”경우를, 너무 많은 일이 같은 예외 유형 있는지 확인도 할 수없는 것

def f(pos_arg, **kwargs):
    no_default = kwargs.pop('no_default')
    has_default = kwargs.pop('has_default', 'default')
    if kwargs:
        raise TypeError('unexpected keyword argument(s) {}'.format(', '.join(sorted(kwargs))))

    print(pos_arg, no_default, has_default)

그리고 행동 :

>>> f(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes exactly 1 argument (3 given)
>>> f(1, no_default='hi')
(1, 'hi', 'default')
>>> f(1, no_default='hi', has_default='hello')
(1, 'hi', 'hello')
>>> f(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
KeyError: 'no_default'
>>> f(1, no_default=1, wat='wat')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in f
TypeError: unexpected keyword argument(s) wat

레시피는 python3.x에서도 똑같이 작동하지만 python3.x 인 경우에는 피해야합니다.


답변

함수를 수신 **args전용 으로 선언 할 수 있습니다 . 그것은 키워드 인자를 요구하지만 유효한 이름 만 전달되도록하기위한 추가 작업이 필요합니다.

def foo(**args):
   print args

foo(1,2) # Raises TypeError: foo() takes exactly 0 arguments (2 given)
foo(hello = 1, goodbye = 2) # Works fine.