본문 바로가기
파이썬

파이썬 namedtuple

by 왕초보 독학 코딩 2024. 1. 7.

파이썬 namedtuple에 대해서 알아보자. 

 

 

 

튜플(tuple)이란?

먼저 튜플(tuple)에 대해서 간단히 알아보자. 파이썬의 튜플은 불변한 순서형 자료형이다. 여러 값을 하나의 변수에 저장하는 데 사용한다. 

user = ('John', 25)
print(f'name: {user[0]}, age: {user[1]}')  # name: John, age: 25

 

튜플은 여러 값을 하나의 변수로 저장하는 장점이 있지만 인덱스로 필드를 접근해야 하므로 가독성이 떨어질 수밖에 없다. 위의 예제에서 user[0]만으로는 name이라는 정보를 알기가 힘들다. 

 

튜플은 불변이므로 값을 변경할 수가 없다.

user[0] = 'Alice'  # 에러 발생

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

 

 

 

namedtuple이란?

파이썬의 namedtuple은 튜플과 유사하지만 필드에 이름을 지정하여 접근할 수 있는 자료구조이다. 이는 기존 튜플의 불변성과 인덱스로 접근하는 특성을 유지하면서 필드에 의미 있는 이름을 부여하여 코드의 가독성을 높일 수 있다. 그리고 튜플의 속성을 그대로 가져가기 때문에 성능도 좋다.

from collections import namedtuple

User = namedtuple('User', ['name', 'age'])
user = User('John', 25)
print(user.name)  # John

 

 

 

namedtuple 정의 방법

namedtuple를 정의하려면 2개의 인자를 전달해야 한다. 첫 번째 인자는 namedtuple의 이름이 되고, 두 번째 인자는 필드 정보가 된다. 필드 정보는 3가지 방법을 사용할 수 있다.

1. 리스트로 전달 : ['name', 'age']

2. 공백으로 구분된 문자열 전달 : 'name age'

3. 콤마로 구분된 문자열 전달 : 'name, age'

User1 = namedtuple('User1', ['name', 'age'])
User2 = namedtuple('User2', 'name age')
User3 = namedtuple('User3', 'name, age')

 

 

필드 이름은 밑줄(_)로 시작하지 않고, 문자, 숫자, 밑줄로 이루어질 수 있다. 그리고 class, for, return 등의 파이썬 키워드는 필드 이름이 될 수 없다. 유효하지 않은 필드이름으로 만드는 경우 에러가 발생한다.

 

namedtuple을 생성할 때 3개의 옵션을 추가할 수 있다.

 

rename

rename을 true로 하면 유효하지 않은 필드 이름을 자동으로 위치 이름으로 대체한다. 위치 이름은 _로 시작하는 인덱스가 된다. 예를 들어 ['name', 'age', 'class']를 전달하면 'class'는 키워드이므로 '_2'가 된다.

User1 = namedtuple('User1', 'name age class', rename=True)
print(User1._fields)  # ('name', 'age', '_2')

 

defaults

defaults는 기본적으로 None으로 되어 있다. 필드의 기본값을 리스트나 튜플로 전달하면 된다. 기본값은 가장 오른쪽 매개변수에 적용된다. 예를 들어, 필드 이름이 ['x', 'y', 'z']이고 기본값이 (1, 2)라면, y의 기본값은 1, z의 기본값은 2가 된다. x는 기본값이 없으므로 필수 인자가 된다.

Point = namedtuple('Point', 'x y z', defaults=[1, 2])
print(Point(0))  # Point(x=0, y=1, z=2)

 

module

module로 설정된 값은 namedtuple의 module 값이 된다. module 값은 namedtuple이 속한 모듈을 나타낸다. 여러 모듈에서 같은 이름의 namedtuple을 사용해도 module이 다르기 때문에 이름 충돌이 발생하지 않는다. module값은 기본적으로 namedtuple을 정의한 곳의 모듈 이름이 된다. 따라서 특별한 경우가 아니라면 module 값을 수정할 필요는 없다.

Person = namedtuple('Person', ['name', 'age', 'gender'], module='my_module')

# module 속성을 통해 명명된 튜플이 속한 모듈의 이름 확인
print(Person.__module__)  # my_module

 

 

 

namedtuple 객체 만들기

정의된 namedtuple은 다양한 방식으로 객체로 만들 수 있다. 위치 인수 또는 키워드 인수로 객체를 만들 수 있고, 필드와 동일한 키를 가지는 딕셔너리를 언패킹해서 객체를 만들 수 있다.

Point = namedtuple('Point', 'x, y')

p1 = Point(0, 0)
p2 = Point(0, y=1)
p3 = Point(x=0, y=2)

p4_dict = {'x': 0, 'y': 3}
p4 = Point(**p4_dict)

 

 

 

메서드와 속성

튜플에서 상속한 메서드 외에도 namedtuple은 세 가지 메서드와 두 가지 속성을 지원한다. 필드 이름과의 충돌을 피하기 위해 이 메서드와 속성의 이름은 밑줄(_)로 시작한다.

 

_make(iterable)

시퀀스 또는 이터러블에서 새로운 객체를 만드는 클래스 메서드이다.

t1 = [1, 2]
t2 = (2, 3)

p1 = Point._make(t1)
p2 = Point._make(t2)

 

_asdict()

필드 이름과 값을 쌍으로 가지는 딕셔너리 객체를 반환한다.

point = Point(11, 22)
print(point._asdict())  # {'x': 11, 'y': 22}

 

_replace(kwargs)

객체의 특정 필드에 새로운 값으로 교체하여 새로운 객체를 반환한다.

p1 = Point(11, 22)
p2 = p1._replace(x=33)

print(p1)  # Point(11, 22)
print(p2)  # Point(33, 22)

 

_fields

필드 이름을 나열한 문자열의 튜플이다. 필드의 구성 및 기존 namedtuple에서 새로운 namedtuple을 만들 때 유용하다.

print(p1._fields)  # ('x', 'y')

 

_field_defaults

기본값을 가지는 필드이름과 기본값을 쌍으로 가지는 딕셔너리이다.

Account = namedtuple('Account', ['type', 'balance'], defaults=[0])

print(Account._field_defaults)  # {'balance': 0}

 

 

 

namedtuple 사용 예제

# 좌표를 나타내는 namedtuple
Point = namedtuple('Point', ['x', 'y'])

# 여러 좌표를 리스트로 관리
points = [Point(x=1, y=2), Point(x=3, y=4), Point(x=5, y=6)]
# name과 age 필드를 가지는 namedtuple
Person = namedtuple('Person', ['name', 'age'])

# name과 age 키를 가지는 딕셔너리 객체를 가지는 data 리스트
data = [{'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 30}]

# 리스트 컴프리해션과 딕셔너리 언패킹으로 Person 객체를 가지는 리스트 만들기
people = [Person(**item) for item in data]
# 정의된 namedtuple의 서브클래스를 만들고, 메서드 확장하기
class ExtendedPoint(Point):
    def distance_from_origin(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

p = ExtendedPoint(x=3, y=4)
print(p.distance_from_origin())  # 5.0

 

'파이썬' 카테고리의 다른 글

파이썬의 던더 메서드  (0) 2024.01.07
파이썬 언패킹  (0) 2024.01.01
파이썬의 str과 repr의 차이점  (0) 2024.01.01