python unpacking

Python의 *와 ** 언패킹(Unpacking) 완벽 이해하기

Python을 공부하다 보면 다음과 같은 코드를 자주 보게 됩니다.

inputs = tokenizer(text, return_tensors="pt")

outputs = model(**inputs)

처음 보면 **가 무슨 의미인지 이해하기 어렵습니다.

**는 곱하기도 아닌데 왜 붙어 있을까?”

이번 글에서는 Python의 언패킹(Unpacking) 개념부터 ***의 차이, 그리고 Hugging Face에서 model(**inputs)를 사용하는 이유까지 자세히 알아보겠습니다.


언패킹(Unpacking)이란?

언패킹(Unpacking)은 하나의 자료구조(List, Tuple, Dictionary)에 들어 있는 값을 꺼내서 함수의 인자로 전달하는 기능​입니다.

Python에서는 두 가지 방법이 있습니다.

  • * : 리스트(Tuple 포함) 언패킹
  • ** : 딕셔너리(Dictionary) 언패킹

1. * : 리스트(Tuple) 언패킹

예를 들어 다음과 같은 함수가 있다고 가정해 보겠습니다.

def add(a, b):
    return a + b

일반적으로는 다음과 같이 호출합니다.

add(3, 5)

하지만 이미 리스트 안에 값이 들어 있다면?

nums = [3, 5]

그대로 넣으면 오류가 발생합니다.

add(nums)

왜냐하면 함수는 인자를 두 개 필요로 하는데, 리스트 하나만 전달했기 때문입니다.

이럴 때 사용하는 것이 *입니다.

add(*nums)

Python은 내부적으로 다음과 같이 변환합니다.

add(3, 5)

즉,

*리스트

첫 번째 값,
두 번째 값,
세 번째 값...

으로 자동 변환됩니다.


예제

def print_name(first, last):
    print(first, last)

name = ["Hong", "GilDong"]

print_name(*name)

실제로는 다음과 같습니다.

print_name("Hong", "GilDong")

2. ** : Dictionary 언패킹

이번에는 Dictionary를 살펴보겠습니다.

def add(a, b):
    return a + b

Dictionary가 다음과 같이 있다고 가정합니다.

params = {
    "a": 3,
    "b": 5
}

이때

add(**params)

라고 작성하면 Python은 내부적으로

add(
    a=3,
    b=5
)

로 변환합니다.

즉,

Dictionary의

Key → 함수의 매개변수 이름

Value → 실제 전달되는 값

이 됩니다.


***의 차이

***
List, TupleDictionary
위치 인자(Positional Argument)키워드 인자(Keyword Argument)
순서대로 전달이름으로 전달

예를 들어

nums = [1, 2, 3]

func(*nums)

func(1, 2, 3)

반면

params = {
    "a":1,
    "b":2,
    "c":3
}

func(**params)

func(
    a=1,
    b=2,
    c=3
)

Hugging Face에서는 왜 **를 사용할까?

Hugging Face의 Tokenizer는 결과를 Dictionary 형태로 반환합니다.

inputs = tokenizer(
    "안녕하세요.",
    return_tensors="pt"
)

출력 예시는 다음과 같습니다.

{
    "input_ids": tensor(...),
    "token_type_ids": tensor(...),
    "attention_mask": tensor(...)
}

반면 BERT 모델의 forward() 함수는 대략 다음과 같이 정의되어 있습니다.

def forward(
    self,
    input_ids=None,
    attention_mask=None,
    token_type_ids=None
):
    ...

즉, 필요한 입력이 모두 키워드 인자입니다.

따라서

model(**inputs)

는 Python이 자동으로 다음과 같이 변환합니다.

model(
    input_ids=inputs["input_ids"],
    token_type_ids=inputs["token_type_ids"],
    attention_mask=inputs["attention_mask"]
)

이렇게 작성하면 필요한 입력이 많아져도 코드를 간결하게 유지할 수 있습니다.


**kwargs는 무엇일까?

PyTorch 모델을 보면 다음과 같은 코드도 자주 등장합니다.

def forward(self, input_ids, **kwargs):
    ...

여기서 **kwargs

“이 함수에 전달되는 추가적인 키워드 인자를 모두 Dictionary 형태로 받겠다.”

는 의미입니다.

argsarguments의 줄임말이며, kwargskeyword arguments의 줄임말입니다.

예를 들어

model(
    input_ids=x,
    attention_mask=mask,
    token_type_ids=token
)

이라면

kwargs

에는

{
    "attention_mask": mask,
    "token_type_ids": token
}

이 저장됩니다.

이를 통해 함수는 필요한 인자만 사용하고, 나머지는 유연하게 처리할 수 있습니다.


정리

Python의 ***는 언패킹을 위한 매우 중요한 문법입니다.

  • *는 리스트나 튜플을 위치 인자로 풀어 전달합니다.
  • **는 Dictionary를 키워드 인자로 풀어 전달합니다.
  • Hugging Face와 PyTorch에서는 Tokenizer가 Dictionary를 반환하기 때문에 model(**inputs)와 같은 형태를 매우 자주 사용합니다.
  • 또한 **kwargs를 사용하면 다양한 추가 인자를 유연하게 처리할 수 있어, 라이브러리와 프레임워크에서 널리 활용됩니다.

처음에는 ***가 낯설게 느껴질 수 있지만, 원리를 이해하면 Python 코드의 가독성과 활용성이 크게 향상됩니다. 특히 머신러닝과 딥러닝 프레임워크를 사용할 때는 거의 필수적으로 접하게 되는 문법이므로 꼭 익혀두는 것을 추천합니다.

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다