Fluent Python - Data Model

Ash-Hun·2024년 5월 4일
0

Fluent-Python

목록 보기
1/1

book cover

파이썬의 데이터 모델에 대한 내용을 담고 있다. 파이썬은 일관성으로 존경받는 언어이지만 우리가 파악하기 어려운 더 세세한 동작원리를 알아둬야할 필요가 있다고 생각한다. 파이썬의 창시자 귀도 반 로섬은 언어설계를 굉장히 잘 하는 소프트웨어 엔지니어로 알려져있는데 이론적으로 덜 아름다워도 프로그래머가 즐거운 언어를 설계할 수 있는 사람이라고 한다. (진짜 대단한 사람...)

이러한 파이썬의 가장 큰 장점중 하나는 일관성이다. 모든 내용을 숙지하지 않아도 어느정도 기능이 동작하는 것을 예측할 수 있다는 것이다. 필자도 전공자이기 때문에 파이썬의 일관성을 굉장히 공감한다. 그러나 다른 객체지향 언어를 배운적이 있다면 헷갈리는 문법도 존재한다. 유독 파이썬만 말이다! 그런 미심쩍은 부분을 우리는 파이썬스러움(Pythonic) 이라고 부르곤 한다. 오늘은 이러한 Pythonic함을 가장 잘 드러낼 수 있는 데이터 모델에 대해 다뤄보겠다.

데이터 모델(Data Model) 은 일종의 프레임워크로서 파이썬을 설명하는 것이라고 생각할 수 있고 구성단위에 대한 인터페이스를 공식적으로 정의한다. 파이썬은 특히나 자체적인 특별한 메서드를 가지는데 이것을 Magic Method라고 한다. 이러한 메서드들은 앞뒤에 더블 언더바를 가지는것이 특징이다. __getitem__() 처럼 말이다.
흔히 개발자들 사이에서는 __getitem()__과 같은 Magic Method를 부를때 "언더바-언더바-getitem"이라고 부르는 사람도 있지만 길고 부르기 어려우니 "던더-getitem"이라고 부르기도 한다. 여기서 "던더"는 "더블 언더바"를 줄여 부르는 것이다.

우리가 이미 알게모르게 Magic Method를 쓰고 있다. 가령 obj[key]형태의 구문에서 특정한 key값에 해당하는 value를 얻고싶다면 우리는 통상적으로 val = obj[your_key]와 같은 형태로 값을 얻지만 실제로 파이썬 인터프리터에서는 obj.__getitem__(key)를 호출하는것이다.


import collections

Card = collections.namedtuple('Card', ['rank', 'suit'])

class FrenchDeck:
    ranks = [str(n) for n in range(2,11)] + list('JKQA')
    suits = 'spaded diamonds clubs hearts'.split()

    def __init__(self) -> None:
        self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]

    def __len__(self):
        return len(self._cards)
    
    def __getitem__(self, position):
        return self._cards[position]

위와 같은 간단한 FrenchDeck Class가 있다고 해보자.
우리는 Deck에서 Card를 반복적으로 가져가고 싶다! 그럴때 __len()____getitem__()의 Magic method를 구현함으로써 자동으로 해당 클래스가 파이썬 시퀀스처럼 작동하게끔 할 수 있는것이다.

deck[:3] # __getitem_() 메서드는 self._cards의 [] 연산자에 작업을 위임하므로 deck 객체는 slicing도 자동으로 지원한다.
Output : 
  [Card(rank='2', suit='spaded'),
   Card(rank='3', suit='spaded'),
   Card(rank='4', suit='spaded')]

즉, 위와 같은 작업이 문제없이 가능한 것이다. FrenchDeck Class에 별다른 조치를 취하지 않아도 말이다! 여기서 굉장히 놀라운것은 파이썬 시퀀스처럼 작동한다는것은 저렇게 순차적으로 객체를 순회할 수도 있지만 전체 크기도, 역순과 정렬도 모두 가능하게 된다는 것을 의미한다.

그렇지만 우리는 명심해야 한다. 원래 Magic Method는 프로그래머가 아닌 Python Interpreter가 호출하기 위해 만들어진 것이라는 점이다. 앞서 한번 말했듯이 len(my_obj)를 호출하면 인터프리터가 my_obj.__len__()를 호출한다는 말을 하는것이다. 만약 my_obj가 사용자 정의 클래스 객체라면 파이썬은 우리가 구현한 __len__() 객체 메서드를 호출한다.

어차피 Magic Method가 호출된다면 앞으로 그것을 호출하는게 좋지않을까?라는 생각이 들수도 있다. 아주 틀린말은 아니지만 맞는말도 아니다. 다만 지금은 미뤄두자. 나중에 더 깊게 알아보게 될 것이다.

이러한 Magic Method는 파이썬 3 데이터 모델 장을 참조하면 더 자세한 내용을 알 수 있다. 약 83개의 종류가 있는데 언젠가 한번씩 동작원리를 알아보면 좋을 것이다.

이제 여러분은 이 질문에 이전과는 다르게 생각해볼 수 있을것이다.
"왜 len()은 메서드가 아닐까?" 어떻게 생각하는가? len(x)는 x가 내장형의 객체일 때 아주 빨리 실행되고 CPython의 내장 객체에 대해서는 그 필드값을 읽어오는 것이다. 즉, len()abs()처럼 특별한 대우를 받아 메서드로 부르지 않지만 Magic Method 덕분에 우리가 직접 정의해서 사용할 수 있는것이다. 즉, 파이썬의 일관성과 내장객체의 효율성 사이의 타협점을 찾은것이라 볼 수 있겠다.


profile
Deep Burst 🔥🔥🔥

0개의 댓글