프로그래밍/python

파이썬(python) 네임드튜플(namedtuple)을 사용해 보자

콘파냐 2017. 5. 19. 01:40
반응형

파이썬의 자료형 중에 네임드튜플(namedtuple)이란 녀석이 있다. 말 그대로 튜플의 성질을 가졌지만 항목에 이름으로 접근이 가능하다.


튜플은 항목에 인덱스(index)로 접근하므로 직관적이지 않다.


튜플의 방식 

mytule[0], mytuple[1], .. 이렇게 하면 0번째, 1번째 항목에 대한 정보를 구체적으로 알 수 없다.


하지만 네임드튜플은 

mytuple.age, mytuple.birth, 와 같이 사용자가 항목에 이름을 붙여 사용할 수 있다.

(물론 인덱스(index)로도 항목에 접근 가능하다.)


그럼 네임드 튜플을 어떻게 사용하는지 살펴보자.


  • from collections import namedtuple

네이드 튜플은 기본 자료형이 아니다. collections 이 제공해주는 namedtuple이라는 함수로 네임드 튜플을 만들어 사용할 수 있다.

>>> Pinfo = namedtuple("biz_card", "name age phone_num")

namedtuple 함수가 반환하는 값은 클래스다. 이 클래스는 biz_card라는 이름을 가진 Pinfo라는 클래스를 만들어 낸다.


Pinfo 클래스의 이름이 두개인건가? 하고 의아해 할 수도 있다. 하지만 이건 다음 예를 보면 이해할 수 있을 것이다.

Cat은 단순히 Dog 클래스를 참조만 하는 변수다. Dog이라는 변수 역시 메모리에 있는 클래스의 실체를 가리키는 변수에 지나지 않는다. Cat으로 대체해도 아무런 문제가 없다.


이런 혼동을 피하려면 네임드 튜플을 사용할 때 다음과 같이 변수 이름을 클래스이름과 통일시키는 것이 깔끔하다.

>>> biz_card = namedtuple("biz_card", "name age phone_num")

처음에 코드를 수정해서 위와 같이 바꾼 후 진행한다.


위와 같이 선언하면 biz_card 클래스는 3개의 속성 name, age, phone_num을 갖을 수 있다.


그리고 다음과 같이 네임드 튜플 객체를 만들 수 있다.

>>> John_card = biz_card("john", 30, "012-322-2131")

여기서 중요한 것은 이렇게 만들어진 네임드 튜플 객체 John은 클래스로부터 만들어졌지만 튜플처럼 속성을 변경하거나 추가할 수 없다는 것이다. 

>>> John_card.new_attr = "새로운 속성 추가 되나?"

Traceback (most recent call last):

  File "<pyshell#10>", line 1, in <module>

    John_card.new_attr = "새로운 속성 추가 되나?"

AttributeError: 'biz_card' object has no attribute 'new_attr'

>>> John_card.age

30

>>> John_card[2]

'012-322-2131'


단지 클래스처럼 속성에 접근이 가능하다. 또한 튜플처럼 인덱스로도 속성(항목)에 접근이 가능하다. 마치 클래스와 튜플을 짬뽕해 놓은 느낌?


네임드 튜플을 사용하는 이유는 가독성?이라고 해야하나?

그리고 한가지 더 사전 대신으로 사용할 수도 있다. 사전 역시 이름(key)으로 값(value)에 접근한다. 그렇다면 사전대신 사용해서 좋은 점은 무엇인가?


아시는 분도 있겠지만 튜플처럼 수정, 변경을 할 수 없는 불변(immutable) 자료형들은 성능상의 이점이 있다.


따라서 수정할 필요가 없다면 사전 대신 네임드 튜플을 사용하는 것이 성능을 위한 좋은 판단이다.


  • 사전과 네임드튜플 간에 전환 방법

네임드튜플을 사전으로 - _asdict 메소드

>>> John_card._asdict()

OrderedDict([('name', 'john'), ('age', 30), ('phone_num', '012-322-2131')])

사전을 네임드튜플로 사전 풀어넣기(**)사용

>>> John_info = {'name': 'john', 'age': 30, 'phone_num': '012-322-2131'}

>>> John_card = biz_card(**my_info)

>>> John_card.phone_num

'012-322-2131'

**는 그냥 쉽게 말해서 사전을 풀어서 각 항목(key와 속성)을 각각의 파라미터로 전달한다. 참고로 *는 튜플이나 리스트와 같은 시퀀스 타입을 풀어서 전달한다. 쉬운 예로들면  4개의 인수를 받는 함수에 *"abcd"라고 인수를 전달하면 각 파라미터에 "a", "b", "c", "d"가 전달된다. 직접 고고싱~

반응형