규도자 개발 블로그

파이썬 함수의 매개변수에 쓰이는 bare asterisk(*)의 의미 본문

Python/Python

파이썬 함수의 매개변수에 쓰이는 bare asterisk(*)의 의미

규도자 (gyudoza) 2022. 5. 21. 10:12

파이썬 함수의 매개변수에 쓰이는 bare asterisk(*)의 의미

def include_router(
        self,
        router: routing.APIRouter,
        *,
        prefix: str = "",
        tags: Optional[List[Union[str, Enum]]] = None,
        dependencies: Optional[Sequence[Depends]] = None,
        responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
        deprecated: Optional[bool] = None,
        include_in_schema: bool = True,
        default_response_class: Type[Response] = Default(JSONResponse),
        callbacks: Optional[List[BaseRoute]] = None,
        generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
            generate_unique_id
        ),
    ) -> None:
        self.rou---

위 함수는 FastAPI에서 앱에 라우터를 등록시키는 함수이다. contribute을 위해서 프레임워크를 까봤을 때 처음 본 파이썬의 형태가 있었는데 바로 위 함수에서 세번째 매개변수로 등록된 bare asterisk이다.

 

너무나도 생소해서 쓰임이 뭘까 궁금했는데 직접 구현하면서 알아보니 프로그램이 사용하는 문법이나 연산과는 관계 없이 함수를 사용하는 사용자(개발자)의 편의를 위한 함수였다. 그런 의미에서 보면 일종의 주석과도 비슷한 의미라 볼 수 있다.

파이썬에서 함수를 처음 배울 때

def function(param, *args, **kwargs):
    print(param)
    print(args)
    print(kwargs)

이런 느낌의 함수를 많이 보았을 것이다.

이런 형태로 함수를 선언하면 처음 선언한 매개변수는 필수가 되고, 추가로 들어가는 익명의 인수는 tuple형태로 args에 추가가 되고, 기명의 인수는 dict형태로 kwargs로 들어간다.

def function(param, *args, **kwargs):
    print(param)
    print(args)
    print(kwargs)

function("this is a param", "noname1", "noname2", yesname1="hi", yesname2="hi2")

===============================================================================
this is a param
('noname1', 'noname2')
{'yesname1': 'hi', 'yesname2': 'hi2'}

이런식으로 말이다.

 

자 그럼 bare asterisk, nameless asterisk는 어떤 역할을 할까. 위에서 말했다시피 아무 역할도 하지 않는다. 그저 사용자의 편의를 위해서 존재한다.

 

위 함수에서 args의 이름을 빼보았다. 바로 오류가 난다. "기명의 매개변수들이 *뒤에 붙어야 합니다". **kwargs처럼 어떤 이름을 때려박더라도 함수에서 작동하는 식은 받아들이지 못한다는 의미이다. 그래서 위 함수는 이렇게 수정할 수 있다.

def function(param, *, yesname1='', yesname2=''):
    print(param)
    print(yesname1)
    print(yesname2)

function("this is a param", yesname1="hi", yesname2="hi2")

===============================================================================
this is a param
hi
hi2

 

정리하자면 bare asterisk의 역할은 python 매개변수를 사용자가 햇갈리지 않게 만들어주는 역할이라고 보면 된다.

 

위처럼 함수를 선언하면 매개변수의 개수를 넘어가는 인수들에대해선 IDE에서 경고도 날려주고 실제 실행도 되지 않는다. 경고 분구를 보면

TypeError: function() takes 1 positional argument but 2 positional arguments (and 2 keyword-only arguments) were given

1개의 포지셔널 인수만 받는데 왜 2개를 넣었냐고 에러를 뱉는다.

 

다시 맨 처음으로 돌아가서

def include_router(
        self,
        router: routing.APIRouter,
        *,
        prefix: str = "",
        tags: Optional[List[Union[str, Enum]]] = None,
        dependencies: Optional[Sequence[Depends]] = None,
        responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
        deprecated: Optional[bool] = None,
        include_in_schema: bool = True,
        default_response_class: Type[Response] = Default(JSONResponse),
        callbacks: Optional[List[BaseRoute]] = None,
        generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
            generate_unique_id
        ),
    ) -> None:
        self.rou---

위에서 봤던 FastAPI의 함수이다. 어떤 용도로 쓰는지 이제 감이 좀 잡힐 것이다. 사용자가 이 함수를 쓸 때 필수로 지정해야 하는 부분은 bare asterisk앞에 두어 직접 지정하지 않으면 오류가 나게 하고, bare asterisk뒤에 있는 매개변수들은 기명의 매개변수로만 접근할 수 있으니 기본값을 두고 사용자가 직접 해당 값을 불러와서 custom할 수 있게만 만들어준 것이다.

 

실제로 이 함수는 bare asterisk를 제거해도 정상적으로 작동한다. 계속 말했듯이 이것의 역할은 연산이 아니라 사용자(개발자) 편의성을 위해 사용하는 것이기 때문이다.

 

 

 

 

 

 

 

 

Comments