TIL 13 | Function Parameter

임종성·2021년 7월 8일
1

Python

목록 보기
2/7
post-thumbnail

함수를 정의할 경우 parameter에 default 값을 정의해줄 수 있다. Default 값이 정의된 parameter는 함수 호출 시 값이 생략되어도 괜찮고, 생략된 경우 default 값이 자동으로 넘겨진다. 다만 default value parameter는 non-default value parameter 앞에 정의될 수 없다. 어째서 정의할 수 없는걸까?

Default Value Parameter vs Non-default Value Parameter

어째서 Default Value Parameter를 Non-default Value Parameter보다 앞에 정의하면 Syntax Error가 발생하는가? 두 parameter의 결정적 차이는 Default Value Parameter는 이미 값이 정의되어 있기에 생략이 가능하다는 점이다. 반면 Non-default Value Parameter는 반드시 값을 정의해주어야 한다.

함수를 호출할 경우 parameter 값은 순서대로 호출되어 각 parameter에 할당될 것이다. 만약 이런 인자 간의 순서가 명확히 정해지지 않는다면, 프로그램은 호출된 값을 어떤 인자에 입력해야 하는지 혼란이 올 것이다. 아래 코드를 살펴보자.


def fun(a = 1, b = 2, c):
	print(c)
	print(b)
    print(a)
    
fun(2, 3)     # Value 2와 3은 어디에 할당될까? a일까, b일까?
fun(4)        # ?

만약 Default Value Parameter가 Non-default Value Parameter 앞에 정의된다고 가정하면, 위 코드에서 Value 2와 3은 어떤 parameter에 할당될까? Parameter a와 b는 값이 정의되어 있기에 생략이 가능하지만, c는 반드시 값을 할당받아야 한다. Value 2나 3을 Parameter c에 할당받는다고 가정하면, 나머지 Value는 어디에 할당될까? 프로그램이 임의로 이를 결정할 수는 없을 것이다.

따라서 혼란을 막기 위해 Default Parameter는 반드시 Non-default Parameter 뒤에 정의되어야 한다는 "룰"을 정하고 이를 어길 시 Syntax Error가 발생하도록 했다고 생각한다.

Variable Length Argument(가변인수)

어떤 함수를 설계할 경우, 몇 개의 Parameter를 받게 될 지 모를 경우가 존재한다. 파이썬에는 이렇게 임의의 개수의 Parameter를 받는 Variable Length Argument(가변인자)가 존재한다.

def function(a, *args): 
	print(a, args) 
    
function(1) # 1 () 
function(1,2) # 1 (2,) 
function(1,2,3,4,5) # 1 (2, 3, 4, 5)

위와 같이 첫 번째 parameter a는 넘겨준 대로 값을 할당받고, 두 번째 인수부터는 인수들을 묶은 튜플 형식으로 받는다.

Variable Length Argument를 사용할 경우 주의할 점이 있는데, 다음과 같은 코드를 보자.

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)

이 코드를 그대로 실행할 경우 다음과 같은 에러가 발생한다.

Traceback (most recent call last):
  File "main.py", line 24, in <module>
    func_param_with_var_args("정우성", "01012341234", "seoul", 20)
TypeError: func_param_with_var_args() missing 1 required keyword-only argument: 'age'

에러의 내용은 함수 호출 시 Parameter age에 할당되야 할 값이 존재하지 않는다는 것이다. 왜 부족한 것일까??

위에서 Variable Length Argument *args임의의 개수의 Parameter를 받는다고 하였고, 곧 몇 개의 parameter를 할당해야 하는지 프로그램이 결정할 수 없다는 것이다.

사용자가 의도했던 것은 age parameter에 value 20을 할당하는 것이었지만 가변인수의 특성상 *args에 value 20이 할당되었고, non-default value parameter인 age는 값을 할당 받지 못해 에러가 발생한 것으로 알 수 있다.

Error 구문에서 왜 missing 1 required positional argument가 아니라 keyword-only argument 라고 나오는 걸까?

정상적으로 출력하기 위해 다음과 같이 코드를 고쳐보았다.

def func_param_with_var_args(name, age, *args):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)

func_param_with_var_args("정우성", 20, "01012341234", "seoul")

함수 정의 부분에서 parater age*args 앞으로 보내어 age가 우선적으로 값을 할당받을 수 있도록 했고, 이에 더불어 함수 호출 부분에서도 age의 value인 20도 두 번째 순서로 조정하였다.

name=정우성
args=('01012341234', 'seoul')
age=20

바꾼 코드로 실행한 결과 결과 값이 잘 도출되는 것을 알 수 있다.

Variable Length Keyword Argument(가변 키워드 인수)

Variable Length Argument가 임의의 개수의 인수를 받는다고 하면, Variable Length Keyword Argument는 임의의 개수의 Keyword Parameter를 받는다.

def function(a, b, **kwargs): 
    print(a, b, kwargs) 

function(1,2,c=3,d=4) # 1 2 {'c': 3, 'd': 4}

다음과 같은 코드를 살펴보자.

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

이 코드를 실행할 경우 다음과 같은 에러가 나타난다.

File "main.py", line 16
  def func_param_with_kwargs(name, age, **kwargs, address=0):
                                                    ^
SyntaxError: invalid syntax

함수의 정의 부분에서 syntax error가 발생한 것을 알 수 있다. Variable Length Argument에서 살펴보았던 코드에서는 모든 positional argument들이 *args 보다 앞에 정의되어야 함을 알 수 있었다. 따라서 같은 맥락으로 모든 keyword argument들이 *kwargs보다 앞에 정의되어야 한다고 생각했고, 다음과 같이 코드를 수정해보았다.

def func_param_with_kwargs(name, age, address=0, **kwargs):
    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")
name=정우성
age=20
kwargs={'mobile': '01012341234'}
address=seoul

수정된 코드를 실행하니 올바른 결과가 도출되는 것을 알 수 있었다.

Variable Length Argument VS Variable Length 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")

이 코드를 실행했더니 다음과 같은 에러가 발생했다.

File "main.py", line 15
  def mixed_params(name="아이유", *args, age, **kwargs, address):
                                                       ^
SyntaxError: invalid syntax

함수의 정의 부분에서 Syntax Error가 일어났다. 이렇듯 비슷한 에러가 발생하는 것을 보아, Function Parameter 간의 필수적으로 정해진 순서가 있음이 명확했다. 참고자료를 통해 조사한 결과, Arguments 간의 정의 순서는 다음 그림과 같다.

크게 3가지 룰을 따르는 것을 알 수 있다.

  • Positional Argument는 Keyword-only Argument 앞에 위치한다.
  • Non-default Parameter는 Default Parameter 앞에 위치한다.
  • Variable Length Arguments는 다른 Positional Argument 뒤에 위치하고, Varialbe Length Keyword Arguments는 다른 Keyword-only Arguments 뒤에 위치한다.

이러한 룰을 바탕으로 위의 코드에서 정의된 함수 인자들의 순서를 고쳐보면 다음과 같다.

def mixed_params(age, name="아이유", *args, address, **kwargs):
    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")

함수에 정의된 5개의 Parameter를 (Regular Positional Argument, Default Argument, Variable Length Argument, Keyword-only Argument, Variable Length Keyword Argument) 순서로 수정했고, 그 결과는 다음과 같다.

name=정우성
args=('01012341234', 'male')
age=20
kwargs={'mobile': '01012341234'}
address=seoul

깔끔하게 결과가 도출된 것을 확인할 수 있다! 그런데 참고 자료를 조사하다보니 문득 생각난 것이 있다.

Error 구문에서 왜 missing 1 required positional argument가 아니라 keyword-only argument 라고 나오는 걸까?

Variable Length Argument 부분에서 위와 같은 궁금증을 품은 적이 있다! 다시금 Function Parameter간의 순서를 살펴보니, *args 다음에 keyword-only argument가 나와야 하기 때문임을 깨달을 수 있었다.

Today I Learned

Default Value Parameter를 Non-default Value Parameter 앞에 정의하면 안되는 이유에 대해서 생각을 해봤는데.. 정의하면 안되는 이유라기 보다는 왜 정의를 못하게 했는가? 에 대한 생각을 하게 되었다.

결국 파이썬이라는 프로그램이 매끄럽게 돌아가고 사용자가 의도한 바를 잘 수행하기 위해 "룰"을 정한 것이라고 생각했고, 그러한 맥락에서 Function Parameter들 간의 순서도 "룰"로 정하여 이를 어길시 Syntax Error가 발생하도록 한 것이라고 생각이 들었다.

결과적으로 Function Parameter 간 순서에 대해 공부하는 시간이었지만, 단순히 순서를 암기하는 것이 아니라 왜 파이썬이 이런 순서를 만들게 되었을까?를 고민하면서 하니 이해가 더 잘 된 느낌이다.

profile
어디를 가든 마음을 다해 가자

0개의 댓글