*args와 **kwargs
*args
입력받은 숫자들을 더해주는 함수를 만든다고 가정해보자.
만약 입력받은 숫자가 2개라면 아래와 같이 함수를 만들면 된다.
def sum_two(a, b):
return a + b
sum_two(3, 5) # 8
마찬가지로 입력받은 숫자가 3개라면,
def sum_three(a, b, c):
return a + b + c
sum_three(3, 5, 7) # 15
하지만 입력받는 숫자가 4개, 5개,... 계속 늘어날 때마다 함수를 새로 짤 수 없는 노릇이고, 또 입력받는 갯수를 알 수 없을 때는 함수를 구현하기가 불가능하다. 물론 list를 이용하면 구현할 수도 있지만 여기서는 다루지 않겠다.
이 때, 함수의 parameter로 *args
를 이용하면 argument들의 수에 구애받지 않는 매력적인 함수를 만들 수 있다.
def sum_args(*args):
sum= 0
for arg in args:
sum+= arg
return sum
sum_args(1, 2, 3, 4) # 10
이 함수는 parameter로 위와 같이 1, 2, 3, 4 라고만 넣어줘도 잘 작동한다. 이 원리는 과연 무엇일까?
다음과 같이 tuple 형태의 자료형을 넣어보면 더 잘 이해할 수 있다.
values = (1,2,3,4)
sum_args(values) # 에러
sum_args(*values) # 10
2번째 줄의 코드는 에러가 뜰 것이고, 3번째 줄의 코드는 위의 경우처럼 잘 작동할 것이다. 그 이유는 앞에 붙은 *
의 역할에서 찾을 수 있다. 앞에 *
을 붙이면 tuple이나 list 형태의 자료를 unpacking하여 반환한다.
unpacking이란 말그대로 포장을 벗겨내는 것, 즉 쉽게 말해 tuple이나 list에서의 괄호나 대괄호를 벗겨낸다고 생각하면 된다. 따라서 3번째 줄의 코드에서 *value
= 1, 2, 3, 4가 되며 이는 tuple이나 list 형태의 자료형이 아니다.
이 값이 다시 sumargs 함수의 parameter로 들어가게 되면 *args
= 1, 2, 3, 4가 된다. 이 말은 거꾸로 args
= (1, 2, 3, 4)가 되며(이 반대의 과정을 *packing*이라 한다.) for 문에서 문제없이 작동하게 된다.
하지만 2번째 줄의 코드에서는 sumargs 함수의 parameter로 tuple 형태의 자료형인 (1, 2, 3, 4)가 그대로 들어가게 되며 *args
= (1, 2, 3, 4)가 된다. *args
에는 unpacking된 값이 들어가야 되는데, packing된 값이 들어갔으므로 에러가 뜬다.
이를 좀 더 활용하면 아래와 같이 코드를 짤 수도 있다.
def myprofile_two(name, age):
print("{name}님의 나이는 {age}입니다.".format(name=name, age=age))
profile_tuple = ("홍길동", 25)
myprofile_two(*profile_tuple) # 홍길동님의 나이는 25입니다.
**kwargs
*args
가 확실히 이해됐다면 **kwargs
도 쉽게 이해될 것이다.
먼저 dictionary형의 데이터를 하나 만들고,
profile_dict= {
"name" : "홍길동",
"age" : 25,
}
아까 위에서 만든 함수를 그대로 사용하여 출력하면
print(myprofile_two(*profile_dict))
name님의 나이는 age입니다.
라는 결과를 얻을 수 있다.
이와 같은 결과가 발생하는 이유는 쉽게 생각해서 *
를 사용하면 포장의 껍질을 한번만 벗겨낼 수 있기 때문이다. 따라서 dictionary의 value 값은 가져오지 못하고, key 값만 argument로 넘겨준다.
우리가 원하는 결과는 value 값들의 출력이므로, 이 때는 **
를 앞에 붙이면 된다.
myprofile_two(**profile_dict) # 홍길동님의 나이는 25입니다.
결과적으로 정리하면, *
은 list나 tuple을 unpacking 해주는 역할을 하고, **
은 dictionary을 unpacking 해준다.
방금은 함수에서 name과 age라는 고정된 2개의 arguments만 받았지만, **kwargs
를 이용하면 함수를 만들면 다음과 같이 argument의 수와 관계없이 처리하는 동적인 함수도 만들 수 있다.
profile_dict_many= {
"name" : "홍길동",
"age" : 25,
"height" : 175,
"country" : "대한민국",
}
def myprofile_kwargs(**kwargs):
for key,value in kwargs.items():
print("{key} = {value}".format(key=key,value=value))
myprofile_kwargs(**profile_dict_many)