이걸 단순히 "디폴트 값 파라미터가 먼저오면 SyntaxError가 발생하잖아요 😓!!"라고 답하면 질문한 사람도 할 말이 없을 것 같다. 하지만 왜 SyntaxError가 발생하는지 찾아보기로 했다.
이것 저것 검색해봐도 구문 자체에 대한 규칙만 설명되어 있을 뿐 정확한 원리나 이유가 설명을 찾을 수가 없었다. SyntaxError가 발생하기 때문이라는 말을 그냥 여러줄에 걸쳐 성의있게 풀어쓴 느낌을 받았기 때문에 속이 시원하지가 않았다. 그러다가 문득 파이썬 문법 자체의 코드를 보면되지 않을까 하고 찾아낸게 CPython이었다. 그러나 코드를 알아볼 길이 없었다. 또르르... 😢😢.
그래서 구글에 cpython function keyword parameter 라고 검색했더니 첫번째 결과에 보이는 스택오버플로우 페이지에서 링크를 타고 넘어가보니 파이썬 문서 하나가 나타났다.
해당 파이썬 문서를 읽어보고 요약한 내용이다. 함수를 호출할 때 argument 처리는 다음과 같은 순서로 진행된다.
formal parameter: 개발자가 사용하는 파라미터의 이름, (positional parameter, keyword parameter 이름들을 합쳐서 부르는 것 같다)
함수의 기본값은 함수 정의에서 한번만 계산된다. 리스트나 딕셔너리같은 mutable한 객체들은 모든 함수 호출에 대해 공유된다.
개인적으로 2번에서 "처음 N개의 슬롯에 위치시킨다" 라는 점 때문에 positional parameter를 함수 정의에서 먼저 선언해달라고 하는 것이 아닐까 추측해본다.
아래 코드를 실행시키면 에러가 발생한다.
def func_param_with_var_args(name, *args, age):
print("name=",end=""), print(name)
print("args=",end=""), print(args)
print("age=",end=""), print(age)
func_param_with_var_args("정우성", "01012341234", "seoul", 20)
고치는 것은 넘나넘나 쉽다.
def func_param_with_var_args(name, age *args):
그러나 이유를 알아보는 것은 넘나넘나 어렵다 🤪.
한 번 고생해서 찾아놓은 파이썬 문서가 이 포스팅을 작성하는데 매우 유용하다.
위에서 말한 formal parameter
의 슬롯보다 더 많은 수의 positional argument가 있다면 TypeError가 발생한다. 하지만 *args
가변인수를 사용한다면, formal parameter는 초과된 수의 positional argument들을 포함하는 튜플 (또는 빈 튜플)을 받을 수 있게된다. 항상 positional argument의 처리가 먼저 이루어지기 때문에 가변 인수의 위치는 그보다 뒤로 가야한다!
참고로
*args
가변인수는 keyword argument 뒤에 올 수도 있지만, 실제로는 keyword argument (**kwargs
포함)보다 먼저 처리된다.
아래의 코드를 실행시키면 에러가 발생한다.
def func_param_with_kwargs(name, age, **kwargs, address=0):
print("name=",end=""), print(name)
print("age=",end=""), print(age)
print("kwargs=",end=""), print(kwargs)
print("address=",end=""), print(address)
func_param_with_kwargs("정우성", "20", mobile="01012341234", address="seoul")
고치는 것은 넘나넘나 쉽다.
def func_param_with_kwargs(name, age, address=0, **kwargs):
그러나 이유를 알아보는 것은 넘나넘나 어렵다 🤪.
만약 formal parameter
의 이름과 keyword argument 인수가 일치하지 않으면 TypeError가 발생한다. 하지만 **kwargs
와 같은 가변 키워드 인수를 사용한다면, formal parameter는 초과된 수의 keyword argument를 딕셔너리 (또는 빈 딕셔너리)형태로 받아들인다. 항상 keyword argument의 처리가 먼저 이루어지기 때문에 키워드 가변 인수의 위치는 그보다 뒤로 가야한다!
아래의 코드를 실행해 보면 에러가 발생한다.
def mixed_params(name="아이유", *args, age, **kwargs, address):
print("name=",end=""), print(name)
print("args=",end=""), print(args)
print("age=",end=""), print(age)
print("kwargs=",end=""), print(kwargs)
print("address=",end=""), print(address)
mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")
고치는 것은 넘나넘나 쉽다.
def mixed_params(age, name="아이유", *args, address, **kwargs):
지금도 이유를 생각해보는게 어려울까? 이제는 아니다!!
어렵지 않다고 말한 이유는 이미 위에서 다 얘기했기 때문이다 ㅋㅋㅋㅋ.
문제의 함수가 호출될 때 인수의 처리과정을 간단히 살펴본다.
1. positional argument 처리 (age)
2. 가변인수 처리 (*args)
3. keyword argument 처리 (name, address)
4. 키워드 가변인수 처리 (*kwargs)
모두 위에서 말한대로 이다! 그런데 이렇게 함수를 작성할 일이 있을까 🤔?
내가 작성한 글이 다른 사람을 한 번에 이해시킬 것 같지는 않다. 문서가 영어로 되어 있어 작문 능력치가 절반은 하락한 듯 하다. 아쉽지만 앞으로 해야할 것들이 있으니 그만하도록 하겠다!
위에 적어놓은 모든 이유를 떠나서 내가 문풍당당하게 생각하는 진짜 이유는 "컴퓨터는 사람이 아니잖아요 😎!" 이다.