Function Parameters

폐쇄맨·2020년 7월 22일
0

WeCode

목록 보기
4/22

1. default value parameter를 non-default value parameter 앞에 선언하면 안되는 이유

이걸 단순히 "디폴트 값 파라미터가 먼저오면 SyntaxError가 발생하잖아요 😓!!"라고 답하면 질문한 사람도 할 말이 없을 것 같다. 하지만 왜 SyntaxError가 발생하는지 찾아보기로 했다.

검색 과정

이것 저것 검색해봐도 구문 자체에 대한 규칙만 설명되어 있을 뿐 정확한 원리나 이유가 설명을 찾을 수가 없었다. SyntaxError가 발생하기 때문이라는 말을 그냥 여러줄에 걸쳐 성의있게 풀어쓴 느낌을 받았기 때문에 속이 시원하지가 않았다. 그러다가 문득 파이썬 문법 자체의 코드를 보면되지 않을까 하고 찾아낸게 CPython이었다. 그러나 코드를 알아볼 길이 없었다. 또르르... 😢😢.
그래서 구글에 cpython function keyword parameter 라고 검색했더니 첫번째 결과에 보이는 스택오버플로우 페이지에서 링크를 타고 넘어가보니 파이썬 문서 하나가 나타났다.

그래서 이유가 뭔데?

해당 파이썬 문서를 읽어보고 요약한 내용이다. 함수를 호출할 때 argument 처리는 다음과 같은 순서로 진행된다.

  1. 각 formal parameter에 대해 비어있는 슬롯들을 만든다.

    formal parameter: 개발자가 사용하는 파라미터의 이름, (positional parameter, keyword parameter 이름들을 합쳐서 부르는 것 같다)

  2. N개의 positional argument가 있다면, 처음 N개의 슬롯에 위치시킨다.
  3. keyword argument가 있다면, 알맞는 슬롯에 채워넣는다. 해당 과정에서 위치시켜야 하는 슬롯이 이미 채워져있으면 TypeError를 발생시킨다.
  4. 여전히 비어있는 슬롯이 있다면, 함수 정의에 있는 기본값을 가져다 채워넣는다. 기본값이 정의되어 있지 않고 채워지지 않은 슬롯이 있다면 TypeError를 발생시킨다.

    함수의 기본값은 함수 정의에서 한번만 계산된다. 리스트나 딕셔너리같은 mutable한 객체들은 모든 함수 호출에 대해 공유된다.

  5. 채워진 슬롯들은 호출에 대한 argument로 사용된다.

개인적으로 2번에서 "처음 N개의 슬롯에 위치시킨다" 라는 점 때문에 positional parameter를 함수 정의에서 먼저 선언해달라고 하는 것이 아닐까 추측해본다.

2. 에러를 고쳐주세요 (위치 인수와 가변 인수의 위치)

아래 코드를 실행시키면 에러가 발생한다.

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 포함)보다 먼저 처리된다.

3. 에러를 고쳐주세요 (가변 키워드 인수의 위치)

아래의 코드를 실행시키면 에러가 발생한다.

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의 처리가 먼저 이루어지기 때문에 키워드 가변 인수의 위치는 그보다 뒤로 가야한다!

4. 에러를 고쳐주세요 (위치 인수와 키워드 가변 인수의 위치)

아래의 코드를 실행해 보면 에러가 발생한다.

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)

모두 위에서 말한대로 이다! 그런데 이렇게 함수를 작성할 일이 있을까 🤔?

소감

내가 작성한 글이 다른 사람을 한 번에 이해시킬 것 같지는 않다. 문서가 영어로 되어 있어 작문 능력치가 절반은 하락한 듯 하다. 아쉽지만 앞으로 해야할 것들이 있으니 그만하도록 하겠다!

위에 적어놓은 모든 이유를 떠나서 내가 문풍당당하게 생각하는 진짜 이유는 "컴퓨터는 사람이 아니잖아요 😎!" 이다.

profile
폐쇄맨

0개의 댓글