Python

PEP-3102 Keyword-Only-Arguments / python method 에서 asterisk(별표) 의미 (*, *args, **kwargs)

뒷골목프로그래머 2023. 3. 3. 17:41
반응형

안녕하세요. 글쓰는 개발자 입니다.

 

 Python 개발을 하다보면 종종 보이는 것이 있습니다. 바로, 흔히들 별표라고 부르는 asterisk, * 입니다. Python 개발자라면 누구나 익히 알고 있듯이 곱셉 연산, unpacking 등에 사용되는 것은 물론, *args / **kwargs와 같이 positional / keword arguments 역할도 할 수 있습니다.

 그런데 최근 단순 궁금증으로 FastAPI의 APIRouter 구현을 뜯어보던 중 FastAPI에 작성된 mutiple arguments를 받는 method들은 대부분 arguments로 asterisk (*)를 포함하고 있었습니다.

그림1. fastapi/routing.py

 '그림1'과 같이 fastapi/routing.py 파일의 APIRouter Class의 add_api_route method를 살펴보면 알 수 있듯이 self, path, endpoint 이후에 한 개의 asterisk가 나타나는 것을 볼 수 있습니다. 타고 넘어가다 보니 FastAPI가 base로 사용한 Starlette 소스코드까지 넘어가게 되었는데 Starlette 전체를 확인하지는 않았지만 잘 찾을 수 없었습니다. (그림2 참고)

그림2. starlette/routing.py

 

 modern Python 문법을 지향하는 FastAPI의 철학을 바탕으로 유추했을 때 가독성 향상 또는 Type Hint와 같이 Bug 발생을 줄이기 위한 목적이 있을 것이라 생각하고 찾아보던 중 PEP 3102"Keyworkd only Arguments"로 명시되어 있음을 확인했습니다.

 

PEP-3102 Keyword Only Arguments

그림3. PEP 3102 - Keyword-Only Arguments

motivation

 postional arguments에 의해 자동으로 채워지지 않을 keyword only arguments 선언을 위해 제안합니다. 현재, python의 method 호출 패러다임은 명시적 keyword와 위치로 arguments를 전달할 수 있습니다. Python은 '남겨진' 인수를 tuple로 varargs 매개 변수에 전달하도록 지정하는 'varargs' 구문(*name)을 사용하여 이를 지원 합니다.

 익히 알고  있는 *args, **kwargs에는 몇 가지 문제가 있습니다. *args의 경우에는 개수의 제한 없이 postional arguments를 전달 할 수 있다는 장점이 있지만 tuple로 확인해야하고 **kwagrs는 keyword로 전달하지만 keyword 네이밍에 제한이 없다는문제가 있습니다. 그리고 많은 사람들이 아래 toggle_activate를 보고 이런 오해를 하고 있습니다.

'toggle_activate method에서 user_id는 postional argument 이고,  is_activate는 keyword argument 이구나.'

def toggle_activate(user_id: str, is_activle: bool=True):
    pass
    
    
# 다양한 method 호출 방식
toggle_activate('test_id)
toggle_activate('test_id', False)
toggle_activate(user_id='test_id')
toggle_activate(user_id='test_id', is_active=False)
toggle_activate(is_active=False, user_id='test_id')

 하지만 위 '다양한 method 호출 방식'을 보면 알 수 있듯이 사실은 둘다 positional 이나 keword arguments로써의 역할을 할 수 있습니다. method의 arguments에 default value가 있는 is_active 값을 변경 할 때 keyword를 명시하다 보니 이런 오해가 종종 발생하고는 합니다.

 

 그리고 이런 오해 때문에 개발자는 method를 만들면서 호출시점에 모두 postional arguments로 할 지? 무엇을 keword arguments로 정해야할지? 어떤 것을 강제해야 할 지? 그리고 keyword arguments로 표시하기 위해 default value는 무엇으로 정하는 것이 좋을지? 와 같은 고민에 빠지게 됩니다. 이러한 고민 해결을 위해 Keyword Only Arguments 도입이 필요합니다.

 

Keyword Only Arguments

 사용 방법은 간단합니다. asterisk (*) 를 method의 arguments로 전달 함으로써, positional arguments 와 keyword only arguments 를 split하는 역할을 합니다. 아래 소스코드를 보시면, asterisk (*) 를 기준으로 text는 positional arguments로 인식되고 뒤에 오는 num, flt 는 keworkd only arguments로써 method 호출 시 반드시 keyword를 명시해야 호출이 가능합니다.

def bare_asterisk(text: str, *, num: int, flt: float):
    pass
    
    
def call_bare_asterisk():
    bare_asterisk('text', num=1, flt=1.1)
    bare_asterisk('text', 1, 1.1)  # Unexpected Arguments Error!!!

 

결론

 우연히 발견하게 된 문법이라 modern python, python 최신 문법 이런 것과 관련 있을 줄 알았는데 의외로 Python 3.0 부터 PEP-3102에 명시되어 있었다고 합니다. 적극적으로 사용해서 견고하고 Bug 발생을 줄이는 코드를 작성하는 데 도움되도록 해야겠습니다.

 

참고

https://peps.python.org/pep-3102/

 

PEP 3102 – Keyword-Only Arguments | peps.python.org

PEP 3102 – Keyword-Only Arguments Author: Talin Status: Final Type: Standards Track Created: 22-Apr-2006 Python-Version: 3.0 Post-History: 28-Apr-2006, 19-May-2006 Table of Contents This PEP proposes a change to the way that function arguments are assign

peps.python.org

https://lukeplant.me.uk/blog/posts/keyword-only-arguments-in-python/

 

Keyword-only arguments in Python

Keyword-only arguments are a feature that has been around since Python 3.0 but I've not seen them used much. This post explores the how and why.

lukeplant.me.uk

 

반응형