본문 바로가기

카테고리 없음

Python : NamedTuple 완벽 가이드: 정의부터 활용까지

 

1. NamedTuple이란?

 

NamedTuple은 Python의 collections 모듈에서 제공하는 클래스의 서브타입으로, 튜플의 장점(불변성과 간결한 데이터 구조)을 유지하면서도 각 요소에 이름을 부여하여 코드의 가독성과 유지보수성을 높여줍니다. 이를 통해 인덱스 번호 대신 이름으로 데이터에 접근할 수 있어 직관적인 코드를 작성할 수 있습니다.

 

주요 특징:

 

불변성: 일반 튜플처럼 생성 후 변경이 불가능합니다.

키 접근 지원: 이름으로 데이터 접근이 가능합니다.

간결한 데이터 구조: 가벼운 클래스처럼 동작합니다.

 

2. 일반 튜플의 단점

 

일반 튜플은 인덱스 번호로 데이터를 접근해야 합니다. 이는 데이터의 의미를 파악하기 어렵게 만들고, 코드의 가독성을 저하시킬 수 있습니다. 

point = (10, 20)

# 인덱스를 사용해야만 데이터에 접근 가능
print(point[0])  # 10
print(point[1])  # 20

 

위 코드는 숫자 1020이 무엇을 나타내는지 파악하기 어렵습니다. 인덱스 번호에 의존하면 실수로 잘못된 데이터를 참조할 가능성도 높아집니다.

또한, 일반 튜플은 단순히 값의 모음이므로, 데이터의 의미를 명시적으로 나타낼 수 없습니다. 이는 특히 복잡한 데이터 구조를 다룰 때 문제가 됩니다.

person = ("Alice", 30, "Engineer")
# person[0], person[1], person[2]만으로는 의미를 알기 어려움

 

데이터의 구조가 변경되었을 때, 일반 튜플은 인덱스를 사용하는 모든 코드를 수정해야 합니다. 반면, NamedTuple은 이름 기반 접근 덕분에 코드 수정 범위가 줄어듭니다.

# 일반 튜플
point = (10, 20)
point = (10, 20, 30)  # 필드 추가 시 기존 코드 전면 수정 필요

# NamedTuple
Point = namedtuple('Point', ['x', 'y', 'z'])
point = Point(10, 20, 30)
print(point.z)  # 추가된 필드도 쉽게 접근 가능

 

일반 튜플은 요소에 대한 타입 정보를 명시적으로 제공할 수 없습니다. 이는 코드 작성 시 타입 안정성을 확보하기 어렵게 만듭니다.

# 일반 튜플
point = (10, 20)  # x와 y가 숫자인지 보장할 수 없음

# NamedTuple은 타입 힌트 제공
from typing import NamedTuple

class Point(NamedTuple):
    x: int
    y: int

 

3. 다양한 선언법

 

아래와 같이 다양한 방법으로 선언 가능합니다. 

from collections import namedtuple

#기본선언
Point = namedtuple('Point',['x','y'])
Point = namedtuple('Point','x,y')
Point = namedtuple('Point','x y')
Point = namedtuple('Point','x y x class', renmae = True)
# x의 경우 키중복이 허용되지 않고, class의 경우 예약어이므로 사용이 불가하지만, 
# rename=True 키워드와 함께 사용가능합니다.

# 인스턴스 생성
p = Point(10, 20)
print(p.x, p.y)  # 출력: 10 20

 

기본값을 포함하여 선언할 수도 있습니다.

Point = namedtuple('Point', ['x', 'y'], defaults=[0, 0])

# 기본값 사용
p1 = Point()         # x=0, y=0
p2 = Point(10)       # x=10, y=0
print(p1, p2)        # 출력: Point(x=0, y=0) Point(x=10, y=0)

 

타입 힌트를 포함한 선언 (typing.NamedTuple)도 가능합니다.

from typing import NamedTuple

class Point(NamedTuple):
    x: int
    y: int

p = Point(10, 20)
print(p.x, p.y)  # 출력: 10 20

 

4. 사용 방법

아래와 같이 다양한 방식으로 사용가능합니다.

# 방법1
p = Point(10, 20)
print(p.x, p.y)  # 출력: 10 20

# 방법2
p = Point(x=10, y=20)
print(p.x, p.y)  # 출력: 10 20

# 방법3
data_dict = {'x':10, 'y':20}
p = Point(**data_dict)
print(p.x, p.y)  # 출력: 10 20

#unpacking
x, y = p
print(x, y)  # 출력: 10 20

 

5.  메소드

필드 정보 확인

print(Point._fields)  # 출력: ('x', 'y')

 

새로운 값으로 업데이트

p = p._replace(x=30)
print(p)  # 출력: Point(x=30, y=20)

 

딕셔너리로 변환

print(p._asdict())  # 출력: {'x': 30, 'y': 20}

 

형 변환

일반 튜플이나 딕셔너리와 상호 변환이 가능합니다.

new_p = Point._make([40, 50])
print(new_p)  # 출력: Point(x=40, y=50)

 

4. 결론

 

NamedTuple은 데이터 구조를 간결하고 명확하게 관리할 수 있는 강력한 도구입니다. 특히, 이름 기반 접근과 타입 힌트의 조합은 유지보수성과 코드 안정성을 크게 향상시킵니다. 데이터가 고정된 구조로 설계되었을 때, 클래스 대신 NamedTuple을 사용하면 가독성과 성능을 동시에 확보할 수 있습니다.