본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] 가변 인자 *args, **kwargs의 언패킹 메커니즘 차이와 3가지 성능 최적화 방법

by Papa Martino V 2026. 3. 4.
728x90

 

가변 인자 *args, **kwargs의 언패킹 메커니즘
패킹(Packing)과 언패킹(Unpacking)

 

파이썬 프로그래밍의 유연성을 상징하는 문법을 꼽으라면 단연 가변 인자(*args, **kwargs)일 것입니다. 함수가 몇 개의 인자를 받을지 미리 정하지 않아도 된다는 점은 데코레이터, API 래퍼, 플러그인 시스템을 설계할 때 엄청난 이점을 제공합니다. 하지만 이 '편리함'의 이면에는 파이썬 인터프리터가 수행하는 패킹(Packing)과 언패킹(Unpacking)이라는 복잡한 과정이 숨어 있으며, 이는 프로그램의 성능 비용(Performance Cost)으로 직결됩니다. 본 포스팅에서는 가변 인자가 내부적으로 어떻게 튜플과 딕셔너리로 변환되는지 그 깊은 곳을 파헤치고, 실제 대규모 연산 환경에서 발생할 수 있는 오버헤드를 줄이는 구체적인 해결 방안을 제시합니다.


1. 가변 인자의 내부 동작: 객체 생성의 마법

함수 정의부에서 *** 기호는 단순히 "여러 개를 받겠다"는 선언을 넘어, 전달된 인자들을 하나의 객체로 묶는 패킹 작업을 수행합니다.

  • *args: 위치 인자(Positional Arguments)를 하나의 Immutable Tuple(불변 튜플)로 묶습니다.
  • **kwargs: 키워드 인자(Keyword Arguments)를 하나의 Mutable Dictionary(가변 딕셔너리)로 묶습니다.

반대로 함수 호출 시 사용되는 ***는 컨테이너에 담긴 데이터를 다시 낱개로 흩뿌리는 언패킹을 수행합니다. 이 과정에서 파이썬은 매번 새로운 객체를 메모리에 할당하고 해제해야 합니다.


2. 가변 인자 처리 방식에 따른 성능 및 특징 차이

일반 인자와 가변 인자를 사용할 때 발생하는 구조적 차이를 정리했습니다.

비교 항목 일반 고정 인자 (Fixed Args) 가변 인자 (*args, **kwargs)
데이터 구조 스택 프레임 내 로컬 변수 직접 할당 Tuple 또는 Dict 객체 생성 및 할당
메모리 비용 매우 낮음 (최적화됨) 상대적으로 높음 (새 객체 생성 오버헤드)
유연성 낮음 (인자 수 고정) 매우 높음 (동적 인자 대응)
바인딩 속도 가장 빠름 패킹/언패킹 단계로 인해 약간 느림

3. Sample Example: 언패킹이 성능에 미치는 영향 측정

실제로 대량의 반복 루프 내에서 가변 인자를 사용할 때 얼마나 많은 성능 비용이 발생하는지 확인해 보겠습니다.


import timeit

# 1. 일반 고정 인자 함수
def fixed_func(a, b, c):
    return a + b + c

# 2. 가변 인자 함수
def var_func(*args):
    return sum(args)

# 성능 측정 (1,000,000번 호출)
fixed_time = timeit.timeit(lambda: fixed_func(1, 2, 3), number=1000000)
var_time = timeit.timeit(lambda: var_func(1, 2, 3), number=1000000)

print(f"Fixed Args 소요 시간: {fixed_time:.4f}s")
print(f"Var Args (*args) 소요 시간: {var_time:.4f}s")

분석: *args를 사용할 경우, 호출할 때마다 새로운 튜플 객체가 생성되어 메모리에 올라갑니다. 비록 파이썬 엔진이 이를 매우 빠르게 처리하도록 최적화되어 있지만, 고성능 수치 계산이나 실시간 처리가 필요한 루프 안에서는 이 비용이 누적되어 병목의 원인이 될 수 있습니다.


4. 고성능 파이썬을 위한 3가지 해결 전략

  1. 불필요한 위임 금지: 단순히 다른 함수로 인자를 전달하기 위해 func(*args, **kwargs)를 남발하는 '패스스루' 패턴은 호출 깊이가 깊어질수록 성능 저하를 일으킵니다. 꼭 필요한 경우가 아니라면 명시적 인자를 사용하세요.
  2. Keyword-Only Arguments 활용: 파이썬 3에서 도입된 def func(*, key1, key2): 구문을 사용하면 **kwargs를 사용하는 것보다 훨씬 빠르고 안전하게 키워드 전용 인자를 처리할 수 있습니다. 딕셔너리 생성 비용을 아끼는 훌륭한 방법입니다.
  3. C-API 및 사이썬(Cython) 고려: 극단적인 성능이 필요하다면 가변 인자 처리를 C 수준에서 최적화하거나, 가변 인자 대신 리스트/배열을 직접 넘기는 설계 변경을 고려해야 합니다.

5. 결론: 유연함과 성능의 트레이드오프(Trade-off)

결론적으로 *args**kwargs는 파이썬의 생산성을 책임지는 강력한 도구이지만, 공짜는 아닙니다. 튜플 패킹딕셔너리 언패킹은 분명히 물리적인 비용을 수반합니다. "언제나 가변 인자를 쓰는 것"보다 "구조가 확정된 곳에는 명시적인 인자를, 확장이 필요한 곳에는 가변 인자를" 사용하는 균형 잡힌 시각이 진정한 전문 개발자의 해결 능력입니다.


내용 출처 및 기술 자료

  • Python Software Foundation. "The Python Tutorial: More on Defining Functions."
  • High Performance Python (Micha Gorelick). "Chapter 3: Lists and Tuples."
  • CPython Internal Source Code: ceval.c (Function call implementation).
728x90