TIL 3.(replit3.) 파이썬의 함수와 keyword-only arguments

jiffydev·2020년 9월 16일
1

1. default value parameter vs non-default value parameter

함수를 정의할 때 default value parameter를 non-default value parameter 앞에 정의 하면 안된다. 그냥 하면 안된다니까 안 쓰고 있는데 막상 왜 안되냐고 하면 답할 수가 없다.
이 문제에 답하기 위해서는 파이썬의 공식 문서를 참조하는 것이 가장 빠르다.

6.3.4. Calls (일부 발췌)

If keyword arguments are present, they are first converted to positional arguments, as follows. First, a list of unfilled slots is created for the formal parameters. If there are N positional arguments, they are placed in the first N slots. Next, for each keyword argument, the identifier is used to determine the corresponding slot (if the identifier is the same as the first formal parameter name, the first slot is used, and so on). If the slot is already filled, a TypeError exception is raised. Otherwise, the value of the argument is placed in the slot, filling it (even if the expression is None, it fills the slot). When all arguments have been processed, the slots that are still unfilled are filled with the corresponding default value from the function definition. 출처

영어에 정신이 혼미해지지만 요약해보면, 파이썬 공식 문서에 따르면 파이썬은 함수를 호출할 때 반드시 인자가 호출될 수 있는지를 평가한 후 호출한다. 그 과정에서 만약 keyword arguments가 존재할 경우, 다음과 같은 과정을 통해 keyword arguments를 positional arguments로 변환한다.

  1. 매개변수의 숫자만큼의 슬롯을 가진 빈 리스트를 만든다. N개의 positional arguments가 있다면 우선적으로 N개의 슬롯을 채운다.
  2. 그 다음, keyword arguments에 대해서는 식별자를 통해 일치하는 슬롯을 찾게 된다.

이 설명에 근거하여 실제 함수로 예를 들어보면

def func(x,y,z):
  return [x,y,z]
func(x=3,1,2)

위 함수에서 keyword argument는 x=3, positional arguments는 1,2이다. 함수를 실행하면 인자 1,2를 먼저 슬롯에 채우게 되고, 함수에 매개변수가 정의된 순서가 x,y,z이므로 x에 1이 y에 2가 할당된다. 그 다음 keyword argument를 할당하게 되면 x에 값이 이미 존재하므로 에러가 발생한다.
그러므로 keyword argument가 존재할 경우에는 반드시 positional argument 뒤에 설정해야 한다.

2. Non-default Keyword-only Argument Error

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)

위 함수를 실행하면 "TypeError: func_param_with_var_args() missing 1 required keyword-only argument: 'age'", age에 인자가 존재하지 않는다고 에러가 나온다. 이는 함수에 정의된 keyword-only argument인 age인자가 호출되지 않은 것으로 파이썬이 인식하기 때문이다.(*args가 20까지 포함하므로) 이를 해결하기 위해서는 호출할 때 keyword인 age와 함께 인자를 전달해 주어야 한다. 그러므로 20에 age keyword를 추가해서 해결.
age keyword를 포함해서 호출하니 문제 없이 함수가 실행된다.

3. Default Keyword-only Argument Error

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")

위 함수를 실행하면 "SyntaxError: invalid syntax", 유효하지 않은 문법 에러가 나온다.
그 이유는 파이썬 문법상 keyword only arguments는 variable length positional arguments와 variable length keyword arguments는 다른 arguments 뒤에 나와야 하기 때문이다. 따라서 함수가 유효하도록 하려면 **kwargs를 가장 뒤로 보내야한다.
**kwargs를 뒤로 보내면 잘 작동하는 것을 볼 수 있다.

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")

위 함수를 실행하면 우선 "SyntaxError: invalid syntax" 에러가 나타나는데, 이는 keyword-only argument 인 address가 variable length keyword argument **kwargs 뒤에 나왔기 때문으로, 우선 이 둘의 위치를 바꿔준다. 다시 실행하면 TypeError: mixed_params() missing 1 required keyword-only argument: 'age' 에러가 나오는데, 2번과 동일하게 age keyword를 추가해서 호출한다.
다만, age=20으로 바꿔도 SyntaxError: positional argument follows keyword argument 에러가 나온다. 이는 말 그대로 호출할 때 keyword argument인 age=20이 positional argument "정우성"보다 먼저 나왔기 때문으로, keyword argument를 뒤로 옮겨주면 해결된다.

5. Variable Length Arguments와 Positional & Keyword Arguments

  • Variable length arguments(가변 길이 인자)는 함수가 받을 인자의 개수가 불분명할 때 사용되는 인자이다.

  • 예상되는 인자의 타입에 따라 사용하는 Variable length arguments종류가 달라지는데 non-keyworded arguments일 때는 *args, keyworded arguments일 때는 **args를 사용한다.

    1. *args
      다수의 non-keyworded argument를 받을 때 사용하며, tuple형식으로 인자를 받는다.
    2. **args
      다수의 keyworded argument를 받을 때 사용하며, 딕셔너리 형식으로 인자를 받는다. 그렇기 때문에 인자가 있을지 없을지 불확실할 때 유용하다. 예를 들어 블로그 포스트를 DB에 저장할 때, 작성자나 글의 내용은 반드시 포함되겠지만 태그나 분류는 작성하지 않는 사람도 있을 것이다. 이 경우 태그와 분류 keyword에 내용이 있을 경우에만 포스트에 함께 저장할 수 있다.
  • Variable Length Arguments와 Positional, keyword arguments를 함께 사용할 때는 다음과 같은 순서로 인자를 사용해야 한다.

    1. Known positional arguments
    2. *args
    3. Known named arguments
    4. **kwargs

    위의 순서를 지키지 않으면 함수가 실행되지 않고 에러가 뜬다. 또한 호출할 때 positional argument는 반드시 그 순서를 지키지 않으면 에러가 뜨므로 주의.

profile
잘 & 열심히 살고싶은 개발자

0개의 댓글