PEP 570 -- Python Positional-Only Parameters에서는 Positional-Only Arguments, Keyword-Only Arguments 개념이 제언되었다. Accepted
상태지만 Python 3.0부터 3.7까지 Keyword-Only Arguments만이 반영되어 있다. 이건 파이썬에서 함수의 인자 형태를 구분하는 방식을 이해하고 있으면 더 알기 쉽다.
함수를 정의하는 입장에서, 인자는 필수(required) 인자와 선택(optional) 인자로 구분할 수 있다. 두 인자의 차이는 기본값 정의 유무이며, 파이썬 인터프리터에서는 이들을 각각 non-default argument, default argument라는 어휘와 섞어 사용한다.
def range_list(start, end, step=1):
return list(range(start, end, step))
print(range_list(0, 5)) # [0, 1, 2, 3, 4]
print(range_list(0, 5, 2)) # [0, 2, 4]
step 만큼의 공차를 가진, start부터 end-1 사이의 등차수열을 만들어 리스트로 반환하는 함수다. print문 부분을 보면 이해가 더 쉽다. 아무튼, 여기서 range_list
함수의 인자 3개를 구분해 보자.
함수를 호출할 때 필수 인자를 모두 채우지 않으면 TypeError
가 발생한다.
def range_list(start, end, step=1):
...
range_list(1) # TypeError: range_list() missing 1 required positional argument: 'end'
여담으로, 선택 인자를 필수 인자 앞에 정의하면 SyntaxError
가 발생함에 주의해야 한다.
def range_list(step=1, start, end): # SyntaxError: non-default argument follows default argument
...
이번 글의 핵심은 이 부분인데, 함수를 호출하는 입장에서 인자는 위치(positional) 인자와 키워드(keyword) 인자로 나뉜다. 함수가 인자를 정의하는 부분에 문법적인 추가 작업을 하지 않았다면, 함수 호출자는 두 가지 방식으로 인자를 전달할 수 있다.
def sum(a, b):
return a + b
print(sum(1, 3))
# a와 b 모두 위치 인자 형태로 전달
print(sum(1, b=3))
# a는 위치 인자, b는 키워드 인자 형태로 전달
print(sum(a=3, b=3))
# a와 b 모두 키워드 인자 형태로 전달
값을 전달할 인자의 이름을 별도로 명시한다면 키워드 인자, 명시하지 않는다면 위치 인자라고 구분하면 된다. 일반적인 함수에 인자를 전달할 때는 위치 인자와 키워드 인자 형태를 마음대로 사용할 수 있는데, PEP 570은 이를 강제하는 문법을 제언한다.
PEP 570에서는 /,
라는 문법을 통해 positional-only를 명시할 수 있도록 제안하고 있다. 실제로 Python 언어 스펙에 반영되어 있는 것은 아니라서 아래의 함수 정의문은 SyntaxError
가 발생하지만, 문법적으로 가능하다고 가정한 채 예제를 작성해 보겠다.
def a(positional_only, /):
...
a(1) # 문제 없음
a(positional_only=1) # TypeError : (대충 이 함수는 positional argument만 받고 있다는 내용)
PEP 570에서는 *,
라는 문법을 통해 keyword-only를 명시할 수 있도록 제안하고 있으며, 이는 실제로 Python 언어 스펙에 반영되어 있다. *
앞의 것들은 positional-or-keyword, 뒤의 것들은 keyword-only argument를 의미하게 된다.
def a(positional_or_keyword, *, keyword_only):
...
a() # TypeError: a() missing 1 required positional argument: 'positional_or_keyword'
a(1) # TypeError: a() missing 1 required keyword-only argument: 'keyword_only'
a(1, 2) # TypeError: a() takes 1 positional argument but 2 were given
a(1, keyword_only=2) # 문제 없음
a(positional_or_keyword=1, keyword_only=2) # 문제 없음
참고로, X-Only Arguments는 단지 hinting만이 아니며 추가적인 문법적 제약을 명시하는 것임을 알고 있어야 한다. 아래처럼, type hinting은 무시해도 되지만 X-Only Arguments 제약은 무시하면 에러가 발생한다.
def a(_: int):
pass
a('') # 에러가 발생하지 않음
def b(*, _):
pass
b() # TypeError: b() missing 1 required keyword-only argument: '_'
오