파이썬의 장점은 일관성이게에 새로운 기능에 대해서도 제대로된 예측을 할 수 있다.
파이썬이 제공하는 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')
사용자가 표준 연산을 수행하기 위해서 클래스 자체에서 구현한 임의 메서드명을 암기할 필요가 없다.
파이썬 표준 라이브러리에서 제공하는 풍부한 기능을 별도로 구현할 필요없이 바로 사용할 수 있다.
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')
...
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에 떠넘길 수 있다.
"""