구조체로 사용할 수 있는 collections.namedtuple

여러 개의 데이터 멤버를 갖는 초간단 클래스를 C 언어에서는 구조체라고 한다.
파이썬에서도 초간단 클래스가 필요하고
namedtuple 모듈을 사용해서 구조체 관련 기능을 지원한다.
늘 이런 기능이 있으면 좋겠다고 생각했었는데.. 찾아볼 생각을 하지 못했다.
"파이썬 라이브러리 레시피"를 읽는 중에 발견한 첫 번째 유용한 기능이다. ^^


def namedtuple(typename, field_names, verbose=False, rename=False)

  • typename : 클래스(자료형)에 사용할 이름
  • field_names : 요소로 사용할 이름들. 리스트 또는 튜플 등의 iterable 객체 전달
  • verbose : 생성된 클래스 명세를 출력할 것인지 말 것인지. True라면 출력.
  • rename : 잘못된 요소 이름을 자동으로 변환. True라면 변환.


from collections import namedtuple

# 'Coordinate'를 전달하는데, coord 변수에 저장하는 것이 처음에는 무척 이상했다.
# coord는 Coordinate 클래스의 별명이라고 보면 된다.
# Coordinate 클래스를 직접 노출시킬 수 없어서 coord로 대신 사용할 뿐이다.
# 그래서, namedtuple 모듈을 사용할 때는
# 변수와 자료형 이름을 동일하게 주는 것이 일반적이다. 다음처럼.
# Coordinate = namedtuple('Coordinate', 'x y z')

# namedtuple을 생성할 수 있는 여러 가지 방법. 문자열 요소 지정도 가능하다.
# coord = namedtuple('Coordinate', 'x y z')
# coord = namedtuple('Coordinate', 'x, y, z')
coord = namedtuple('Coordinate', ['x', 'y', 'z'])

# 변수를 만드는 여러 가지 방법
# pos = coord(1.2, 3.4, 5.6) # position argument
# pos = coord(x=1.2, y=3.4, z=5.6) # keyword argument
pos = coord._make((1, 2, 3)) # class method

print(pos) # Coordinate(x=1, y=2, z=3)
print(pos.x, pos.y, pos.z) # 1 2 3

# 쓸모는 없지만, 반복문에 적용할 수 있다.
for i in pos:
print(i) # 1 2 3

print(pos._fields) # ('x', 'y', 'z')
print('coord :', coord) # coord : <class '__main__.Coordinate'>

print('-'*50)
# locals 함수를 호출하면, coord는 있지만 Coordinate는 보이지 않는다.
# 그래서, Coordinate 클래스를 직접 사용할 수 있는 방법은 존재하지 않는다.
# 중요한 점은 coord가 <class '__main__.Coordinate'>라고 되어 있기 때문에
# Coordinate 클래스처럼 사용할 수 있다는 점이다.
print(locals()) # {'pos': Coordinate(x=1, y=2, z=3),
# 'namedtuple': <function namedtuple at 0x10cb977b8>,
# 'coord': <class '__main__.Coordinate'>,
# 'i': 3}

print('-'*50)

# 일반 클래스를 만들어서 확인해 보면
# 클래스 변수 d는 출력에 object라고 되어 있고 메모리 주소가 표시된다.
# 메모리를 할당 받은 변수라는 뜻이다.
# 반면 클래스 이름인 Dummy는 클래스 이름만 출력된다.
# 다시 말해 클래스 이름만 출력되면, 클래스 변수를 만들 수 있는 키워드라는 뜻이 되는 것이다.

class Dummy:
pass

d = Dummy()
print(d) # <__main__.Dummy object at 0x10fce4b70>
print(type(d)) # <class '__main__.Dummy'>
print(Dummy) # <class '__main__.Dummy'>


아래 코드는 namedtuple 함수가 생성하는 클래스 명세다.
verbose 매개변수를 True로 설정하면 볼 수 있다.

# coord = namedtuple('Coordinate', 'x, y, z', verbose=True)

from builtins import property as _property, tuple as _tuple
from operator import itemgetter as _itemgetter
from collections import OrderedDict

class Coordinate(tuple):
'Coordinate(x, y, z)'

__slots__ = ()

_fields = ('x', 'y', 'z')

def __new__(_cls, x, y, z):
'Create new instance of Coordinate(x, y, z)'
return _tuple.__new__(_cls, (x, y, z))

@classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
'Make a new Coordinate object from a sequence or iterable'
result = new(cls, iterable)
if len(result) != 3:
raise TypeError('Expected 3 arguments, got %d' % len(result))
return result

def _replace(_self, **kwds):
'Return a new Coordinate object replacing specified fields with new values'
result = _self._make(map(kwds.pop, ('x', 'y', 'z'), _self))
if kwds:
raise ValueError('Got unexpected field names: %r' % list(kwds))
return result

def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + '(x=%r, y=%r, z=%r)' % self

def _asdict(self):
'Return a new OrderedDict which maps field names to their values.'
return OrderedDict(zip(self._fields, self))

def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return tuple(self)

x = _property(_itemgetter(0), doc='Alias for field number 0')

y = _property(_itemgetter(1), doc='Alias for field number 1')

z = _property(_itemgetter(2), doc='Alias for field number 2')

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

pprint : 쉽고 예쁘게 출력하기  (0) 2017.04.09
enum 클래스  (0) 2017.04.09
defaultdict 사용법  (0) 2017.04.06
정규분포와 누적분포 비교 그래프  (0) 2017.04.06
defaultdict와 딕셔너리 응용 코드  (0) 2017.04.06