파이썬 데이터 모델

매일 공부(ML)·2022년 10월 26일
0

Fluent Python

목록 보기
1/130

Chapter1 파이썬 데이터 모델

1.1 파이썬 카드 한 벌

파이썬의 장점은 일관성이게에 새로운 기능에 대해서도 제대로된 예측을 할 수 있다.

파이썬이 제공하는 API를 이용하면 고유의 객체를 정의하여 대부분의 파이썬 상용구르 적용할 수 있다.

던더 메서드특별 메서드처럼 앞뒤에 이중 언더바를 갖고 있다.

예시

obj[key] 형태의 구분이 getitem()처럼 특별 메서드의 지원으로 my_collection[key]를 평가하기 위한 인터프리터는 my_collection.getitem(key)를 호출한다.

  • 반복, 컬렉션, 속성 접근, 연산자 오버로딩, 함수 및 메서드 호출,
  • 객체 생성 및 제거, 문자열 표현 및 포맷, 블록 등 콘텍스트 관리

#일련의 카드로 구성한 카드 한 벌
import collections

"""
collections.namedtuple()을 이용해서 개별 카드가 나타내는 클래스를 구현
namedtuple를 이용하면, 데이터베이스의 레코드처럼 메서드를 가지지 않는 일련의 속성으로 구성된 클래스 만들기

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

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

    def __init__(self):
        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]

beer_card = Card('7','diamonds')
beer_card #Card(rank='7', suit='diamonds')

deck = FrenchDeck()
len(deck)#52

deck[0] #Card(rank='2', suit='spades')

deck[-1]#Card(rank='A', suit='hearts')

#random.choice() 메서드를 활용하여 시퀀스 진행

from random import choice
choice(deck) #Card(rank='K', suit='diamonds')

choice(deck)#Card(rank='4', suit='diamonds')

choice(deck) #Card(rank='K', suit='clubs')

Points

  • 사용자가 표준 연산을 수행하기 위해서 클래스 자체에서 구현한 임의 메서드명을 암기할 필요가 없다.

  • 파이썬 표준 라이브러리에서 제공하는 풍부한 기능을 별도로 구현할 필요없이 바로 사용할 수 있다.

  • getitem()메서드는 self._cards의 []연산자에 작업을 위임하기에 deck 객체는 슬라이싱도 자동으로 지원한다.

#__getitem__() 특별 메서드를 구현함으로 deck 반복

for card in deck: #doctest: +ELLIPSIS
    print(card)
...
Card(rank='2', suit='spades')
Card(rank='3', suit='spades')
Card(rank='4', suit='spades')
Card(rank='5', suit='spades')
Card(rank='6', suit='spades')
...

for card in reversed(deck): #doctest: +ELLIPSIS, 뒤에서 부턱 반복
    print(card)

...
Card(rank='A', suit='hearts')
Card(rank='K', suit='hearts')
Card(rank='Q', suit='hearts')
Card(rank='J', suit='hearts')
Card(rank='10', suit='hearts')
...

  • 컬렉션에 contains() 메서드가 없다면 in 연산자는 차례대로 검색한다.
Card('Q','hearts') in deck #True
Card('7', 'beasts') in deck #False
  • 정렬하기
"""
규칙
스페이드, 하트, 다이아몬드, 클로버 순으로 정한다.
숫자로 순위를 정한다,
"""

suit_values = dict(spades=3, hearts=2, diamonds=1, clubs = 0)

def spades_high(card):
    rank_value = FrenchDeck.ranks.index(card.rank)
    return rank_value * len(suit_values) + suit_values[card.suit]
    
for card in sorted(deck, key=spades_high): #doctest: +ELLIPSIS
    print(card)
    
...

for card in sorted(deck, key=spades_high): #doctest: +ELLIPSIS
    print(card)
    
...
Card(rank='2', suit='clubs')
Card(rank='2', suit='diamonds')
Card(rank='2', suit='hearts')
Card(rank='2', suit='spades')
Card(rank='3', suit='clubs')
...

"""
FrenchDeck이 암묵적으로 object를 상속받지만, 상속 대신 데이터 모델과 구성을 이용하여 기능을 가져온다.

__len__()과 __getitem__()특별 메서드를 구현함으로써 FrenchDeck는 표준 파이썬 시퀀스처럼 작동하므로 반복 및 슬라이싱 등의 핵심 언어 기능 및 random의 choice(), reversed(), sorted()함수를 사용한 예제에서 본 것처럼 표준 라이브러리를 사용할 수 있다.

구성 덕분에 __len__()과 __getitem() 메서드는 모든 작업을 list 객체인 self._cards에 떠넘길 수 있다.
"""
profile
성장을 도울 아카이빙 블로그

0개의 댓글