오늘은 간단하게 함수의 정의에서 흔히 볼 수 있는 *args와 **kwargs에 대해 간단하게 알아보겠습니다.

 


 먼저 *args는 positional arguments들을 받는 무언가를 의미합니다. 그리고 positional arguments는 문서에 따르면 keyword 인자가 아닌 것을 의미합니다. 무슨 이야기인지 모르겠으니, 예제를 한 번 봅시다.

 

 

 하나는 1과 3을, 다른 하나는 1, 3, 7, 13을 인자로 넘겨줍니다. 함수 a는 args에 있는 모든 원소를 출력하는데요. 어떤 값들이 출력되는지 보겠습니다.

 

 

 1과 3을 인자로 가지는 함수 a를 호출했을 때에는 1, 3이 출력됩니다. 그리고 1, 3, 7, 13을 인자로 가지는 함수 a를 호출했을 때에는 1, 3, 7, 13이 출력됨을 알 수 있어요. 잠깐. 그러면 동적으로 positional argument를 받을 때 유용할 수 있겠습니다. 사실, built in 함수에서도 이러한 것을 사용하는 예제를 꽤나 쉽게 찾을 수 있습니다.

 

 zip 함수를 보겠습니다.

 

 뭔가 많아 보이는데, 문서를 잘 보면 *iterables가 붙어 있습니다. iterables한 것 1개 또는 그 이상을 받아서 처리 가능하다는 것을 의미합니다.

 

 1번째 zip 함수는 6개의 iterable한 인자를 받았습니다. 그리고, 2번째 zip 함수는 7개의 iterable한 인자를 받았습니다. 아니 대체 zip 함수가 어떻게 동작하길래, 저렇게 argument를 동적으로 받아버릴까요?

 

 

 하나는 zip([1, 2])를, 다른 하나는 zip([1, 2], [3])을 받았다고 해 봅시다. [1, 2]만 받은 쪽입니다.

 

 

 그리고 이 쪽은 [1, 2], [3] 이렇게 두 개를 받았습니다.

 

 전자는 [1, 2]에서 1번째 원소만 소비하고 yield를 시킬 겁니다. 그러면 1번째 yield 시점에, (1)만 뽑아낼 겁니다.

 

 반면에, [1, 2]와 [3]을 넘겨받은 zip은 1번째 yield 시점에 (1, 3)을 뽑을 겁니다. 핵심은 *iterable 이라는 키워드를 통해 여러 개의 argument를 동적으로 받아먹었다는 것입니다. 아니면 다소 쉬운 예로 인자로 넘어간 모든 원소의 합을 생각해 봅시다.

 

 

 이건 어떤가요? my_sum에 2개의 정수 인자를 넘기던, 4개의 정수 인자를 넘기던 인자의 합이 반환됩니다. 동적으로 positional 인자를 받아먹을 때 유용하게 쓰일 법 합니다. 왜냐하면 클라이언트가 my_sum을 호출할 때 인자를 2개만 넘길 수도 있고, 4개만 넘길 수도 있기 때문입니다.

 

 


 그러면 **kwargs는 무엇일까요? 이것은 keyword argument들을 받는 무언가를 의미합니다. 문서에서는 arg=와 같이 식별자로 넘기거나, 혹은 **{"a": 1, "b":2}와 같이 딕셔너리로 넘기는 경우를 예로 들고 있는데요.

 

 

 함수 a가 있어요. 그런데 7번째 줄에서는 foo=1, na=2를 넘겨줍니다. 이는 키워드 foo의 값은 1, na의 값은 2로 넘겨줬다는 의미입니다. 다음에 8번째 줄에서는 키워드 na의 값을 3으로 넘겨줍니다. 9번째 줄에는 키워드 nara의 값을 10으로 넘겨줘요. 이제 a 함수를 봅시다. a 함수를 보면, kwargs의 전체를 순회하면서, 키 값과 kwargs[k], 즉 value 값을 출력하는데요. 어떻게 출력되는지 보겠습니다.

 

 

 보시면 1번째 a함수의 경우 foo의 값은 1이고, na의 값은 2라고 출력하고 있습니다. 2번째 a함수는 na의 값이 3이라는 정보만 출력합니다. 그리고 3번째의 경우, nara의 값이 10이라는 정보만 출력합니다. 즉, 동적으로 키워드 arguments들을 받을 때 써먹으면 유용해 보입니다. query parameter 같이 optional하게 파라미터를 받을 수 있는 경우에도 잘 쓰일 법 하겠습니다.