Python 함수에서는 전달되는 인자의 개수를 미리 정하기 어려운 경우가 있습니다. 이때 여러 개의 인자를 하나로 묶어서 함수 내부에서 처리할 수 있는데, 이를 파라미터 패킹(Parameter Packing)이라고 합니다.
앞서 살펴본 파라미터 언패킹이 하나의 값을 여러 인자로 풀어 전달하는 방식이었다면, 패킹은 반대로 여러 인자를 하나의 객체로 묶는 방식입니다.
Python에서는 *args와 **kwargs를 사용해 이러한 작업을 할 수 있습니다.
파라미터 패킹이란?
먼저 일반적인 함수를 생각해 보겠습니다.
def add(a, b):
return a + b
이 함수는 두 개의 인자를 받을 수 있습니다.
print(add(10, 20))
그런데 세 개, 네 개처럼 전달되는 인자의 개수가 계속 달라진다면 매개변수를 일일이 추가해야 합니다.
이때 *args를 사용할 수 있습니다.
def add_all(*args):
return sum(args)
이제 원하는 개수만큼 값을 전달할 수 있습니다.
print(add_all(10, 20))
print(add_all(10, 20, 30))
print(add_all(10, 20, 30, 40))
결과:
30
60
100
여기서 전달된 여러 인자는 args라는 하나의 튜플로 묶입니다.
*args의 동작 방식
다음 코드를 보면 패킹이 어떻게 이루어지는지 쉽게 확인할 수 있습니다.
def show(*args):
print(args)
show(10, 20, 30)
결과:
(10, 20, 30)
함수 내부의 args는 튜플입니다.
즉,
show(10, 20, 30)
으로 전달된 여러 개의 위치 인자가 내부에서는 다음과 같이 하나로 묶입니다.
args = (10, 20, 30)
이것이 *args를 이용한 파라미터 패킹입니다.
args라는 이름은 정해져 있는 것이 아니다
args라는 이름이 특별한 문법인 것은 아닙니다.
중요한 것은 앞에 붙은 *입니다.
다음과 같이 다른 이름을 사용할 수도 있습니다.
def show(*numbers):
print(numbers)
show(10, 20, 30)
결과:
(10, 20, 30)
하지만 Python에서는 일반적으로 여러 위치 인자를 받을 때 *args라는 이름을 관례적으로 사용합니다.
따라서 다른 개발자가 코드를 봤을 때도 쉽게 이해할 수 있습니다.
일반 매개변수와 *args 함께 사용하기
*args는 일반적인 매개변수와 함께 사용할 수도 있습니다.
def calculate(operation, *numbers):
print(operation)
print(numbers)
호출하면 다음과 같습니다.
calculate("sum", 10, 20, 30)
결과:
sum
(10, 20, 30)
첫 번째 "sum"은 operation에 들어가고 나머지 값들은 numbers에 튜플 형태로 묶입니다.
이런 구조는 고정된 값과 여러 개의 가변적인 값을 함께 받아야 할 때 유용합니다.
**kwargs를 이용한 키워드 인자 패킹
*args가 여러 위치 인자를 묶는 방법이라면 **kwargs는 여러 키워드 인자를 묶는 방법입니다.
def show_info(**kwargs):
print(kwargs)
다음과 같이 호출할 수 있습니다.
show_info(name="철수", age=20, major="Python")
결과:
{'name': '철수', 'age': 20, 'major': 'Python'}
여기서 kwargs는 딕셔너리입니다.
즉 여러 개의 키워드 인자가 하나의 딕셔너리로 묶입니다.
{
"name": "철수",
"age": 20,
"major": "Python"
}
args와 kwargs의 차이
두 문법의 차이를 정리하면 간단합니다.
| 문법 | 패킹되는 인자 | 함수 내부 자료형 |
|---|---|---|
*args | 위치 인자 | 튜플 |
**kwargs | 키워드 인자 | 딕셔너리 |
예를 들어:
def example(*args, **kwargs):
print(args)
print(kwargs)
다음과 같이 호출할 수 있습니다.
example(10, 20, name="철수", age=20)
결과:
(10, 20)
{'name': '철수', 'age': 20}
10, 20은 args에 들어가고 name, age는 kwargs에 들어갑니다.
*args와 **kwargs를 함께 사용하는 이유
두 가지를 함께 사용하면 함수가 매우 유연해집니다.
예를 들어 다음과 같은 함수를 만들 수 있습니다.
def print_info(*args, **kwargs):
print("일반 인자:", args)
print("키워드 인자:", kwargs)
호출:
print_info(10, 20, name="철수", age=20)
결과:
일반 인자: (10, 20)
키워드 인자: {'name': '철수', 'age': 20}
이런 방식은 어떤 종류의 인자가 얼마나 전달될지 미리 정하기 어려운 함수를 만들 때 사용할 수 있습니다.
*args는 튜플이므로 일반적인 튜플처럼 사용할 수 있다
args는 튜플이기 때문에 인덱스를 사용하거나 반복문으로 순회할 수 있습니다.
def show_numbers(*args):
for number in args:
print(number)
show_numbers(10, 20, 30)
결과:
10
20
30
또한 sum()과 같은 내장 함수와 함께 사용할 수도 있습니다.
def calculate_sum(*args):
return sum(args)
print(calculate_sum(10, 20, 30, 40))
결과:
100
**kwargs는 딕셔너리처럼 사용할 수 있다
kwargs는 딕셔너리이므로 키와 값을 이용해서 데이터를 처리할 수 있습니다.
def show_user(**kwargs):
print(kwargs["name"])
print(kwargs["age"])
show_user(name="철수", age=20)
결과:
철수
20
반복문을 사용해 모든 값을 확인할 수도 있습니다.
def show_user(**kwargs):
for key, value in kwargs.items():
print(key, value)
show_user(name="철수", age=20, major="Python")
결과:
name 철수
age 20
major Python
파라미터 패킹과 언패킹 비교
패킹과 언패킹은 서로 반대되는 개념입니다.
패킹:
def show(*args):
print(args)
show(10, 20, 30)
여러 개의 인자가 하나의 튜플로 묶입니다.
언패킹:
numbers = (10, 20, 30)
show(*numbers)
하나의 튜플에 들어 있던 값이 다시 여러 개의 인자로 풀립니다.
간단하게 정리하면 다음과 같습니다.
패킹
여러 개의 인자 → 하나의 객체
언패킹
하나의 객체 → 여러 개의 인자
같은 * 기호가 사용되지만 함수를 정의할 때 사용하는지, 호출할 때 사용하는지에 따라 역할이 달라진다는 점이 중요합니다.
실무에서는 어디에 사용할까?
*args와 **kwargs는 다양한 Python 라이브러리와 프레임워크에서도 볼 수 있습니다.
특히 다른 함수에 인자를 그대로 전달하는 함수를 만들 때 유용합니다.
예를 들어 다음과 같은 형태입니다.
def wrapper(*args, **kwargs):
return some_function(*args, **kwargs)
wrapper()에 전달된 위치 인자와 키워드 인자를 다시 some_function()에 전달하는 구조입니다.
이러한 패턴은 함수의 동작을 추가하거나 기존 함수를 감싸는 래퍼(wrapper)를 만들 때 활용할 수 있습니다.
다만 모든 함수에 *args와 **kwargs를 사용하는 것이 좋은 것은 아닙니다. 함수가 받아야 하는 매개변수가 명확하다면 일반적인 매개변수를 사용하는 편이 코드를 이해하기 쉽습니다.
파라미터 패킹 핵심 정리
이번 글의 핵심은 다음과 같습니다.
*args는 여러 개의 위치 인자를 하나의 튜플로 묶습니다.**kwargs는 여러 개의 키워드 인자를 하나의 딕셔너리로 묶습니다.args,kwargs라는 이름 자체가 특별한 것은 아닙니다.*와**가 패킹을 나타내는 핵심 문법입니다.- 패킹과 언패킹은 서로 반대되는 개념입니다.
*args,**kwargs는 인자의 개수가 유동적인 함수를 만들 때 유용합니다.
마무리
Python의 파라미터 패킹은 함수에 전달되는 여러 인자를 하나의 객체로 묶어서 처리하는 기능입니다.
가장 기본적인 형태는 다음 두 가지입니다.
def example(*args):
pass
여러 위치 인자를 튜플로 받는 방식입니다.
def example(**kwargs):
pass
여러 키워드 인자를 딕셔너리로 받는 방식입니다.
특히 *args와 **kwargs는 Python 라이브러리나 프레임워크의 코드를 읽다 보면 자주 만나게 되므로 기본적인 동작을 이해해 두는 것이 좋습니다.
다음 글에서는 함수 자체를 하나의 값처럼 다룰 수 있는 함수 객체(Function Object)에 대해 알아보겠습니다.