[Python] namedtuple 다시 정리

Hyeseong·2020년 12월 11일
0

python

목록 보기
13/22
post-thumbnail

네임드 튜플은 어디에 적합?

기본 tuple데이터 타입의 확장이라고 생각하면 쉽게 이해된다.(튜플은 불변구조)


tup = ('hello', object(), 42)
tup
('hello', <object at 0x2028d05a290>, 42)
print(tup[2])
42
tup[2] = 23
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-0bbb7d46192a> in <module>
----> 1 tup[2] = 23

TypeError: 'tuple' object does not support item assignment

튜플의 단점 -

1) 정수 인덱스를 써야함
2) 개별 속성에 이름 지정 불가
3) 1,2번의 이유로 가독성 Down
4) 결국 버그를 쉽게 만듬


네임드 튜플은 기존 튜플의 문제점 해결

네이드 튜플은 immutable 속성.
한 번만 쓰고 여러번 읽는다는 원칙
고유한(사람이 읽을 수 있는) 식별자를 통해 각 객체에 접근 할 수 있다.
구체적으로 정수 인덱스를 기억하거나 기업을 돕기 위한 정수 상수를 정의하는 등의 대안을 선택할 필요 없음

from collections import namedtuple
Car = namedtuple('Car', 'color mileage')

첫 번째 매개변수, '타입명' - 함수 호출 및 생성시 이름
그럼 두 번째 매개변수는 무엇인데 띄워쓰기를 하는 것일까?

'color mileage'.split()
['color', 'mileage']
Car = namedtuple('Car', ['color', 'mileage']) # 두번째 매개변수를 리스트로 전달한 방법.
my_car = Car('red', 3812.4)
print(my_car.color)
print(my_car.mileage)
red
3812.4
print(my_car[0]) # 인덱스를 사용하여 접근 가능
red
color, mileage = my_car # 튜플 풀기와 
print(color, mileage, end='\n') 
print(*my_car) # 언팽킹이 사용된 모습
red 3812.4
red 3812.4

my_car
Car(color='red', mileage=3812.4)
my_car.color = 'blue' # 변경 불가능
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-40-f0c9bbb41ef0> in <module>
----> 1 my_car.color = 'blue'

AttributeError: can't set attribute

네임드튜플 객체는 내부적으로 일반 파이썬 클래스로 구현되요. 메모리 사용량도 일반 클래스보다 '좋으며' 일반 튜플만큼 메모리 효율적이고요.

즉, '네임드튜플은 파이썬에서 불변 클래스를 수동으로 정의할 때 사용할 수 있는 메모리 효율적인 지름길이다'라고 생각하는 것이 좋아요.

네임드 튜플 상속하기

네임드튜플 객체에 메서드를 추가할 수도 있어요. 예를들어 다른 클래스와 마찬가지로 네임드 튜플로부터 클래스를 확장하고 그런 방식으로 메서드와 새 속성을 추가할 수 있어요.

Car = namedtuple('Car', ['color', 'mileage'])

class MyCarWithMethods(Car):
    def hexcolor(self):
        if self.color == 'red':
            return '#ff0000'
        else:
            return '#000000'

이제 MyCarWithMethods 객체를 만들고 hexcolor() 메서드를 호출할 수 있어요.

c = MyCarWithMethods('red', 1234)
c.hexcolor()
'#ff0000'

이 방식은 다소 거추장스러워요. 불변 속성들로 구성된 클래스를 만들기 원한다면 할 만한 가치가 있을지 모르지만 누워서 침뱉기다.
예. 네임드 튜플의 내부적인 구성 방식 때문에 새로운 '불변'필드를 추가하기가 까다롭다. 네임드 튜플 계층을 만드는 가장 쉬운 방법은 기본 튜플의 _fields 속성을 사용하는 거에요.

Car = namedtuple('Car', ['color', 'mileage'])

ElectricCar = namedtuple(
    'ElectricCar', Car._fields+('charge',)
)

이렇게 하면 원하는 결과를 얻을 수 있다.

ElectricCar('red', 1234, 45.0)
ElectricCar(color='red', mileage=1234, charge=45.0)

내장 도우미 메서드

fields 속성 외에도 각 네임드 튜플 인스턴스는 유용한 몇 가지 도우미 메서드를 제공한다. 이 메서드들의 이름은 모두 하나의 밑줄 문자()로 시작한다. 이 문자는 보통 해당 메서드나 속성이 클래스 또는 모듈의 안정된 공개 인터페이스의 일부가 아니라 '프라이빗(Private)'임을 뜻한다.

하지만 네임드 튜플의 경우 밑줄명명 규칙은 다른 의미를 갖는다. 밑줄로 시작하는 도우미 메서드 및 속성은 네임드 튜플의 공개 인터페이스에 포함된다.

사용자 정의 튜플 필드와의 충돌을 피하기 위해 밑줄을 사용했을 뿐이다. 따라서 필요하다면 사용해라!

네임드 튜플 도우미 메서드가 도움이 될 수 있는 몇 가지 시나리오를 보여주겠다.

`_asdict()' 도우미 메서드의 사용을 보장!.

특징: 네임드 튜플의 내용을 딕셔너리로 반환함.



my_car._asdict()
{'color': 'red', 'mileage': 3812.4}

JSON 출력을 생성할 때 필드 이름의 오타를 피하는 데 유용하다. 예를들면 다음과 같다.

import json
json.dumps(my_car._asdict())
'{"color": "red", "mileage": 3812.4}'

또 다른 유용한 도우미인 _replace() 함수는 튜플의 (얕은)복사본을 생성하고 필드의 일부를 선택적으로 대체 할 수 있다.

my_car._replace(color='blue')
Car(color='blue', mileage=3812.4)

마지막으로 _make() 클래스 메서드를 사용하여 객체 시퀀스나 반복 가능 객체로부터 새로운 네임드튜플 인스턴스를 생성할 수 있다.

Car._make(['red',999])
Car(color='red', mileage=999)

namedtuple의 장점

데이터를 잘 구조화하여 코드를 정돈하고 이는 가독성 UP
형식에 구애 받지 않음(예. 딕셔너리 -> 네임드튜플)
구조화 되지 않은(튜플,딕셔너리) -> 네임드튜플처럼 구조화되면(협업UP)

요점 정리

  • collection.namedtuple은 불변 클래스를 수동으로 정의하는 메모리 효율적인 지름길
  • 네임드 튜플은 데이터를 이해하기 쉬운 구조로 만들어 주는 코드를 정리하는 데 도움이 될 수 있다.
  • 네임드튜플은 유용한 도우미 메서드를 몇 가지 제공한다. 이 메서들의 이름은 모두 밑줄 하나로 시작하지만, 공개 인터페이므로 사용해도 OK
profile
어제보다 오늘 그리고 오늘 보다 내일...

0개의 댓글