Skip to main content

*args와 **kwargs

학습 목표

  • 위치 인자와 키워드 인자의 차이를 이해한다
  • *args로 가변 위치 인자를 받을 수 있다
  • **kwargs로 가변 키워드 인자를 받을 수 있다
  • 매개변수 순서 규칙을 올바르게 적용할 수 있다

왜 중요한가

가변 인자는 유연한 함수 인터페이스를 설계하는 핵심 도구입니다. ML/DL에서 하이퍼파라미터를 딕셔너리로 전달하거나, 래퍼(Wrapper) 함수를 작성할 때 *args**kwargs는 필수입니다.

위치 인자와 키워드 인자

def greet(name, greeting):
    print(f"{greeting}, {name}!")

# 위치 인자 - 순서대로 매핑
greet("김철수", "안녕하세요")

# 키워드 인자 - 이름으로 매핑
greet(greeting="반갑습니다", name="이영희")

# 혼합 - 위치 인자가 먼저
greet("박민수", greeting="환영합니다")

*args (가변 위치 인자)

*args는 여러 개의 위치 인자를 튜플로 받습니다.
def total(*args):
    """모든 인자의 합을 반환합니다."""
    print(f"받은 인자: {args}")  # 튜플
    return sum(args)

print(total(1, 2, 3))          # 6
print(total(10, 20, 30, 40))   # 100

# 일반 매개변수와 함께
def first_and_rest(first, *rest):
    print(f"첫 번째: {first}")
    print(f"나머지: {rest}")

first_and_rest(1, 2, 3, 4)
# 첫 번째: 1
# 나머지: (2, 3, 4)

**kwargs (가변 키워드 인자)

**kwargs는 여러 개의 키워드 인자를 딕셔너리로 받습니다.
def print_info(**kwargs):
    """모든 키워드 인자를 출력합니다."""
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="김철수", age=25, city="서울")
# name: 김철수
# age: 25
# city: 서울

# 설정 함수 패턴
def configure(**options):
    defaults = {"lr": 0.001, "epochs": 10, "batch_size": 32}
    defaults.update(options)  # 기본값 덮어쓰기
    return defaults

config = configure(lr=0.01, epochs=50)
print(config)  # {"lr": 0.01, "epochs": 50, "batch_size": 32}

*args와 **kwargs 함께 사용

def flexible(*args, **kwargs):
    print(f"위치 인자: {args}")
    print(f"키워드 인자: {kwargs}")

flexible(1, 2, 3, name="test", value=42)
# 위치 인자: (1, 2, 3)
# 키워드 인자: {"name": "test", "value": 42}

매개변수 순서 규칙

# 올바른 순서
def func(pos, /, pos_or_kw, *, kw_only, **kwargs):
    pass

# 순서: 위치 전용 → 일반 → *args → 키워드 전용 → **kwargs
def complete(a, b, *args, option=True, **kwargs):
    print(f"a={a}, b={b}")
    print(f"args={args}")
    print(f"option={option}")
    print(f"kwargs={kwargs}")

complete(1, 2, 3, 4, option=False, extra="hello")

키워드 전용 인자 (*)

* 뒤의 매개변수는 반드시 키워드로 전달해야 합니다.
def train(model, *, epochs, lr, batch_size=32):
    """키워드 전용 매개변수로 실수 방지"""
    print(f"epochs={epochs}, lr={lr}, batch_size={batch_size}")

# train(model, 10, 0.01)     # TypeError!
train(model, epochs=10, lr=0.01)  # 올바른 호출

위치 전용 인자 (/)

Python 3.8+에서 / 앞의 매개변수는 반드시 위치로 전달해야 합니다.
def power(base, exp, /):
    """위치 전용 매개변수"""
    return base ** exp

print(power(2, 10))            # 1024
# power(base=2, exp=10)        # TypeError!

언패킹으로 인자 전달

# 리스트/튜플 언패킹 → 위치 인자
def add(a, b, c):
    return a + b + c

numbers = [1, 2, 3]
print(add(*numbers))   # 6

# 딕셔너리 언패킹 → 키워드 인자
params = {"a": 10, "b": 20, "c": 30}
print(add(**params))   # 60

AI/ML에서의 활용

# 래퍼 함수 패턴 - 원본 함수의 모든 인자를 그대로 전달
def timed_function(func):
    """실행 시간을 측정하는 래퍼"""
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - start
        print(f"{func.__name__}: {elapsed:.4f}초")
        return result
    return wrapper

# 하이퍼파라미터 딕셔너리 전달
hyperparams = {
    "learning_rate": 0.001,
    "num_epochs": 50,
    "batch_size": 32,
    "dropout": 0.3,
}

def build_model(**kwargs):
    print(f"모델 설정: {kwargs}")

build_model(**hyperparams)

# 여러 데이터셋 처리
def process_datasets(*datasets, normalize=True):
    results = []
    for ds in datasets:
        if normalize:
            ds = (ds - ds.mean()) / ds.std()
        results.append(ds)
    return results
아닙니다. ***가 중요하며, 이름은 관례일 뿐입니다. *values, **options 등으로 사용해도 됩니다. 하지만 *args, **kwargs가 Python 커뮤니티의 표준 관례입니다.
train(model, 10, 0.01, 32) 같은 호출은 각 숫자가 무엇을 의미하는지 알기 어렵습니다. train(model, epochs=10, lr=0.01) 처럼 강제하면 코드의 의도가 명확해집니다.

체크리스트

  • *args**kwargs의 차이를 설명할 수 있다
  • 매개변수 순서 규칙을 올바르게 적용할 수 있다
  • ***를 사용한 언패킹으로 인자를 전달할 수 있다
  • 키워드 전용 인자(*)의 필요성을 이해한다

다음 문서