반응형

Fluent Python 2판 깃허브 저장소에 있는 코드를 분석해보고 있습니다. 

https://github.com/fluentpython/example-code-2e 



2024. 1. 18 최초작성




이름붙은 튜플(collections)을 다루어봅니다.

 

# https://github.com/fluentpython/example-code-2e/blob/master/01-data-model/data-model.ipynb
# Chapter 1 -- The Python Data Model
# A deck as a sequence of playing cards

import collections
# collections 모듈을 사용하면 collections 컬렉션을 사용할 수 있습니다.
# collections는 튜플처럼 순서를 가진 컬렉션이지만 필드에 이름을 부여할 수 있습니다.

Card = collections.namedtuple('Card', ['rank', 'suit'])
# 'Card' 이름의 튜플을 생성합니다. 이 튜플은 2개의 값을 저장하는데 각각 'rank'와 'suit'라는 이름을 가집니다.


# 이름있는 튜플 Card를 선언하고 포함된 갯수와 지정한 인덱스의 값을 가져오는 클래스를 정의합니다.
class FrenchDeck:
    # FrenchDeck 클래스의 클래스 변수 ranks와 suits를 선언합니다.

    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    # print(ranks)
    # ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
    # 앞 부분은 숫자 2 ~ 10까지를 문자로 바꾼 리스트를 생성하고 뒷부분은 J,Q,K,A 문자를 포함하는 리스트를 생성하여 둘을 더합니다.
   
    suits = 'spades diamonds clubs hearts'.split()
    # print(suits)
    # ['spades', 'diamonds', 'clubs', 'hearts']
    # 공백을 기준으로 문자열을 분리하여 리스트에 저장합니다.

    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]
        # 클래스 변수 suits와 ranks에 저장된 리스트로부터 값을 꺼내와 튜플 Card에 저장하여 클래스 변수 _cards에 대입합니다.

    def __len__(self):
        return len(self._cards)
        # 클래스 변수 _cards의 원소 개수를 리턴합니다.

    def __getitem__(self, position):
        return self._cards[position]
        # 클래스 변수 _cards의 인덱스 position에 있는 값을 출력합니다.
   

# beer_card = Card('7', 'diamonds')
# print(beer_card)
# # Card(rank='7', suit='diamonds')
# # 시험삼아 Card 튜플에 값을 저장하고 출력해봅니다.

# 클래스 FrenchDeck의 인스턴스를 생성하면 __init__ 함수에 의해서 이름 있는 튜플 Card에 값이 채워집니다.
deck = FrenchDeck()

# # 인스턴스 deck에 저장되어있는 원소의 개수가 출력됩니다.
# print(len(deck))
# # 52

# # 인스턴스 deck에 저장되어있는 첫번째 원소와 마지막 원소를 출력합니다.
# print(deck[0])
# # Card(rank='2', suit='spades')
# print(deck[-1])
# # Card(rank='A', suit='hearts')


from random import choice

# print(choice(deck))
# # Card(rank='9', suit='spades')
# # 무작위로 하나의 값을 선택합니다. 코드를 실행할때 마다 값이 달라지게 됩니다.

# print(deck[:3])
# # [Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
# # 처음 3개의 원소를 출력합니다.

# print(deck[12::13])
# # [Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
# # 인덱스 12부터 시작하여 13 간격으로 원소를 리스트에 저장합니다.


# for card in deck:
#     print(card)
# # 인스턴스 deck에 있는 원소를 순서대로 출력합니다.



# for card in reversed(deck):
#     print(card)
# # 인스턴스 deck에 있는 원소를 역순서대로 출력합니다.


# 인스턴스 deck에 해당 튜플이 있는지 체크합니다.
# print(Card('Q', 'hearts') in deck)
# # True
# print(Card('7', 'beasts') in deck)
# # False


suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
# # 각 카드 무늬에 가중치를 부여하기 위해 딕셔너리를 생성합니다.
# print(suit_values)
# # {'spades': 3, 'hearts': 2, 'diamonds': 1, 'clubs': 0}

def spades_high(card):
    rank_value = FrenchDeck.ranks.index(card.rank)
    # 카드의 순위(rank)에 해당하는 인덱스를 가져옵니다. 이 인덱스는 '2'에서부터 시작하여 'A'에서 끝나는 순서입니다.

    return rank_value * len(suit_values) + suit_values[card.suit]
    #  이 순위 인덱스 rank_value에 len(suit_values)(무늬의 개수, 여기서는 4)를 곱하고, 해당 카드 무늬의 가중치(suit_values[card.suit])를 더합니다. 이로써 각 카드에 고유한 점수를 부여합니다.

for card in sorted(deck, key=spades_high):
# sorted 함수는 deck에 있는 카드들을 spades_high 함수에 정의된 규칙에 따라 정렬합니다.
# key=spades_high는 정렬 기준으로 spades_high 함수의 반환 값을 사용한다는 의미입니다.
    print(card)

# 이 코드의 목적은 카드 덱을 특정한 순서(스페이드, 하트, 다이아몬드, 클럽 순으로 그리고 각 무늬 내에서는 '2'부터 'A'까지의 순서)에 따라 정렬하고, 이를 출력하는 것입니다.




Vecor 클래스를 정의하여 Vector 데이터 타입을 생성하고 몇가지 연산을 재정의해봅니다.

 

# https://github.com/fluentpython/example-code-2e/blob/master/01-data-model/data-model.ipynb
# Example 1-2. A simple two-dimensional vector class
import math


# Vector 클래스를 정의합니다.
class Vector:

    # 주어진 두개의 값을 클래스 변수 x,y에 저장합니다.
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    # Vector 클래스의 인스턴스를 출력시 어떻게 출력할지를 정합니다.
    def __repr__(self):
        return 'Vector(%r, %r)' % (self.x, self.y)

    # abs 함수에서 Vector 클래스의 인스턴스를 어떻게 계산한지를 정합니다. - 벡터의 크기를 계산합니다.
    def __abs__(self):
        return math.hypot(self.x, self.y)

    # bool 함수에서 Vector 클래스의 인스턴스를 어떻게 계산한지를 정합니다. - 원점이면 False, 그외에는 True를  반환합니다.
    def __bool__(self):
        return bool(abs(self))

    # + 연산에서 Vector 클래스의 인스턴스를 어떻게 계산한지를 정합니다. - 벡터의 덧셈을 계산합니다.
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Vector(x, y)

    # * 연산에서 Vector 클래스의 인스턴스를 어떻게 계산한지를 정합니다. - 벡터와 스칼라곱을 계산합니다.
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
   

v0 = Vector(0, 0)
v1 = Vector(2, 4)
v2 = Vector(2, 1)


print(v1)
# Vector(2, 4)
print(v2)
# Vector(2, 1)


print(abs(v1))
# 4.47213595499958


print(bool(v0))
# False
print(bool(v1))
# True


print(v1 + v2)
# Vector(4, 5)


print(v1 * 3)
# Vector(6, 12)


반응형

문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.

도움이 되셨다면 토스아이디로 후원해주세요.
https://toss.me/momo2024


제가 쓴 책도 한번 검토해보세요 ^^

+ Recent posts