Python(파이썬): NamedTuple

파이썬에는 튜플인데 딕셔너리 성격을 가진 튜플인 NamedTuple이 있다. 튜플의 성격처럼 불변형이라서 중요한 데이터를 담는 데 유용하다. 뿐만 아니라 일반 튜플과 달리 직관적으로 무슨 데이터인지 알 수 있게 데이터 모델링이 가능하다. ‘NamedTuple’ 알고 있으면 정말 유용하게 사용할 수 있을 것 같아서 정리해보았다.

NamedTuple 사용 방법

collections의 namedtuple를 import 합니다. 직원의 이름, 부서, 연봉 데이터를 담는 데이터를 namedtuple로 만들고 싶다고 가정하면 아래와 같이 선언 및 인스턴스를 생성을 할 수 있습니다. 선언은 클래스를 생성하는 것으로 보고, 이에 데이터를 인자로 넣어서 인스턴스를 생성하는 형식과 유사하다고 보면 될 것 같습니다.

# nametuple 선언
Staff = namedtuple('Staff_info', ['name', 'department', 'salary'])
# 객체 생성
staff1 = Staff('홍길동', '영업', '4000')
print(staff1)

결과

Staff_info(name='홍길동', department='영업', salary='4000')

NamedTuple 선언 방법

namedtuple을 선언하는 방법은 위의 사용 방법에서도 소개했지만 위 방법도 포함하여 크게 3가지 방법으로 선언이 가능합니다.

from collections import namedtuple

# 속성을 리스트로 선언
Staff1 = namedtuple('Staff_info', ['name', 'department', 'salary'])
# 속성을 쉼표 분리로 선언
Staff2 = namedtuple('Staff_info', 'name, department, salary')
# 속성을 띄어쓰기로 선언
Staff3 = namedtuple('Staff_info', 'name department salary')

NamedTuple 인스턴스 생성 방법

NamedTuple 인스턴스 생성 방법 4가지

namedtuple을 선언하고 이를 이용하여 데이터를 입력하는 방법 (인스턴스를 생성하는 방법)은 4가지 방법이 있습니다.

# 객체 생성
## 방법1
staff1 = Staff1(name='홍길동', department='영업', salary=4000)
## 방법2
staff2 = Staff1('고길동', '마케팅', 5000)
## 방법3
other_dict = {'name':'둘리', 'department':'전략/기획', 'salary':6000}
staff3 = Staff1(**other_dict)
## 방법4
other_list = ['또치', '경영', 7000]
staff4 = Staff1._make(other_list)

# 출력
print(staff1)
print(staff2)
print(staff3)
print(staff4)

결과

Staff_info(name='홍길동', department='영업', salary=4000)
Staff_info(name='고길동', department='마케팅', salary=5000)
Staff_info(name='둘리', department='전략/기획', salary=6000)
Staff_info(name='또치', department='경영', salary=7000)

리스트 컴프리핸션을 이용한 NamedTuple 인스턴스 생성

리스트 컴프리핸션을 사용하면 NamedTuple 인스턴스를 손쉽게 대량을 생성할 수 있습니다

Classes = namedtuple('Classes', ['rank', 'number'])
students = [Classes(rank, number) 
                    for rank in 'A B C'.split() 
                        for number in [str(n) for n in range(1,5)]]
print('리스트컴프리핸션을 이용한 namedtuple 생성:',students)

결과

리스트컴프리핸션을 이용한 namedtuple 생성: [Classes(rank='A', number='1'), Classes(rank='A', number='2'), Classes(rank='A', number='3'), Classes(rank='A', number='4'), Classes(rank='B', number='1'), Classes(rank='B', number='2'), Classes(rank='B', number='3'), Classes(rank='B', number='4'), Classes(rank='C', number='1'), Classes(rank='C', number='2'), Classes(rank='C', number='3'), Classes(rank='C', number='4')]

NamedTuple 인스턴스 데이터에 접근법

namedtuple은 튜플과 같이 인덱스로 접근 할 수도 있고 클래스의 필드로 접근 할 수도 있습니다. 또한 unpaking해서 변수로 할당 할 수도 있습니다.

print('인덱스로 접근:',staff1[0], staff1[1], staff1[2])
print('클래스 속성으로 접근:', staff2.name, staff2.department, staff2.salary)
# unpacking
name, dept, sal = staff3
print('unpacking:', name, dept, sal)

결과

인덱스로 접근: 홍길동 영업 4000
클래스 속성으로 접근: 고길동 마케팅 5000
unpacking: 둘리 전략/기획 6000

NamedTuple 장점

데이터 모델링 가능

데이터 모델링이 가능하다는 말은 데이터를 구조화 할 수 있다는 뜻이다. 그냥 튜플과 namedtuple이 어떻게 다른가 아래 예제를 보고 확인할 수 있습니다. 튜플은 선언한 것만을 보았을 때 무슨 내용인지 알 수 없습니다. 본인이 어떤 내용인지 코딩 당시에는 기억하더라도 시간이 지나면서 까먹게 됩니다… 주석에도 한계가 있으며 특히 프로젝트 협업 과정에 코드와 데이터양이 많아지면 정말 힘들어지게 됩니다…
반면, Namedtuple은 데이터가 구조화 되어 있는 것을 볼 수 있습니다. 1은 학년을 의미하고, 25는 학생 수를, 40.4는 남녀 비율을, 2는 반 등수를 홍길동은 선생님 이름이라는 것을 한 눈에 알 수 있습니다.

from collections import namedtuple

# Tuple
class_data = (1, 25, 40.4, 2, '홍길동')
print('tuple:', class_data)

# NamedTuple
Classes = namedtuple('Class_unit', ['grade', 'student_number', 'male_female_ratio', 'rank', 'teacher'])
c1 = Classes(1, 25, 40.4, 2, '홍길동')
print('namedtuple:',c1)

결과

tuple: (1, 25, 40.4, 2, '홍길동')
namedtuple: Class_unit(grade=1, student_number=25, male_female_ratio=40.4, rank=2, teacher='홍길동')

메모리 효율성

namedtuple 인스턴스는 딕셔너리보다 메모리 효율적 입니다. 아래 코드는 단순한 예제이지만 namedtuple이 메모리를 적게 사용하는 것을 알 수 있습니다. 대용량 데이터를 다룬다면 namedtuple이 좋은 옵션이 될 수 있을 것 같습니다.

import sys
from collections import namedtuple

# namedtuple 선언
PersonNamedTuple = namedtuple('PersonNamedTuple', ['name', 'age', 'city'])

# namedtuple 인스턴스 생성
person_namedtuple = PersonNamedTuple(name='John', age=30, city='New York')

# 딕셔너리 생성
person_dict = {'name': 'John', 'age': 30, 'city': 'New York'}



# 메모리 사용량 비교
print(f"Memory usage of namedtuple: {sys.getsizeof(person_namedtuple)} bytes")
print(f"Memory usage of dictionary: {sys.getsizeof(person_dict)} bytes")

결과

Memory usage of namedtuple: 64 bytes
Memory usage of dictionary: 184 bytes

튜플, 딕셔너리로 호환가능

namedtuple은 원한다면 튜플 혹은 딕셔너리로 언제든 변환하여 사용할 수 있습니다.

# tuple로 변환
print(tuple(staff1))  # ('홍길동', '영업', 4000)

# dictionary로 변환
print(staff1._asdict())  # {'name': '홍길동', 'department': '영업', 'salary': 4000}

데이터 처리 용이

필드의 기본값을 지정할 수 있어 누락된 값을 처리하는 편리한 방법을 제공합니다. ‘defaults’ 매개변수에 각 필드에 대한 기본값을 튜플로 입력해주면 됩니다. 인스턴스를 생성하는 동안 필드를 지정하지 않으면 defaults로 지정해준 기본값을 사용합니다.

from collections import namedtuple

# nametuple 선언 시, 디폴트값 지정
Person = namedtuple('Person', ['name', 'age', 'city'], defaults=('Unknown', 0, 'Unknown'))

# 특정 필드값을 입력 안하고 인스턴스 생성
person1 = Person(name='John', age=30)
person2 = Person(name='Alice')

# 출력
print(person1)  # Output: Person(name='John', age=30, city='Unknown')
print(person2)  # Output: Person(name='Alice', age=0, city='Unknown')

Leave a Comment

목차