Pythonオブジェクト向けプログラミングガイド読書ノート

12739 ワード

第一部は特殊な方法でPythonスタイルのクラスを実現する
より良い拡張性を実現するために、Python言語は多くの特殊な方法を提供しており、大きく以下のいくつかの種類に分けられています.
  • プロパティアクセス
  • 呼び出し可能オブジェクト
  • 集合
  • 数字
  • コンテキスト
  • 反復器
  • 第一章使用_init()__方法
    Python中所有的事物都対象!!!!!!_init__()メソッドは2点を覚えます.
  • __init()__(初期化)はオブジェクトのライフサイクルの開始であり、各オブジェクトが正しく初期化されなければ正常に動作しません.
  • __init__()は、
  • を割り当てることができる
    オブジェクトのライフサイクルは、主に作成、初期化、破棄されます.'暗黙的ではなく表示:各_についてinit__()メソッドは、初期化する変数を設定して表示する必要があります.オブジェクトを作成するたびにpythonは空のオブジェクトを作成し、そのオブジェクトの_を呼び出します.init__()関数は、初期化された操作を提供します.
    #  21       。
    class Card(object):
        def __init__(self, suit, rank):
            self.suit = suit
            self.rank = rank
            self.hard, self.soft = self._points()
    
    
    class NumberCard(Card):
        def _points(self):
            return int(self.rank), int(self.rank)
    
    
    class AceCard(Card):
        def _points(self):
            return 1, 11
    
    
    class FaceCard(Card):
        def _points(self):
            return 10, 10
       
    class Suit(object):
        def __init__(self,name,symbol):
            self.name = name
            self.symbol = symbol
    
    Club,Diamond,Heart,Spade = Suit('Club','♣'),Suit('Diamond','♦'),Suit('Heart','♥'),Suit('Spade','♠')

    ファクトリ関数で呼び出す_init__():
    
    def card(rank, suit):
        if rank == 1:
            return AceCard('A', suit)
        elif 2 <= rank < 11:
            return NumberCard(str(rank), suit)
        elif 11 <= rank < 14:
            name = {11: 'J', 12: 'Q', 13: 'K'}[rank]
            return FaceCard(name, suit)
        else:
            raise Exception("rank out of range")
                rank     suit   card  .
    deck = [card(rank, suit) for rank in range(1, 14) for suit in (Club, Diamond, Heart, Spade)]
    print(deck[0].rank,deck[0].suit.symbol)

    このコードは52枚のカードオブジェクトの作成を完了した.
    マッピングとクラスを使用して設計を簡略化する.
    クラスは第1レベルのオブジェクトであるためrankパラメータからオブジェクトに射出することは容易である.次のカード類工場はマッピングを用いて実現されたバージョンである.
    def card4(rank,suit):
        class_ = {1:AceCard,11:FaceCard,12:FaceCard,13:FaceCard}.get(rank,NumberCard)
        return class_(rank,suit)

    マッピングロジックを修正する必要があり、Cardサブクラスを提供するほか、rankオブジェクトの文字列結果を提供する必要がある.この2つの部分のマッピングをどのように実現するかには、4つの一般的なスキームがある.
  • は、2つの並列マッピング
  • を確立することができる.
  • は、1つの二元グループにマッピングすることができる.
  • はpartial()関数としてマッピングすることができる.
  • は、クラス定義を修正する完了マッピングロジック.1を考慮することができる.パラレルマッピング
  • def card5(rank,suit):
        class_ = {1:AceCard,11:FaceCard,12:FaceCard,13:FaceCard}.get(rank,NumberCard)
        rank_str = {1:'A',11: 'J', 12: 'Q', 13: 'K'}.get(rank,str(rank))
        return class_(rank_str,suit)

    これは行う価値がなく、マッピングキー1,11,12,13の論理的重複をもたらす.
    パラレル構造を使用しないでください.パラレル構造は元祖またはより良い組み合わせに置き換えられるべきです.
  • は、1つの額面値のタプル
  • にマッピングされる.
    def card6(rank,suit):
       class_,rank_str= {
           1:(AceCard,'A'),
           11:(FaceCard,'J'),
           12:(FaceCard,'Q'),
           13:(FaceCard,'K')
       }.get(rank,(NumberCard,str(rank)))
       
       return class_(rank_str,suit)

    rank値からクラスオブジェクトにマッピングする場合は珍しく、2つのパラメータはオブジェクトの初期化に1つしかない.rankから比較的簡単なクラスや関数オブジェクトにマッピングする、目的の不明確なパラメータを提供する必要がないのが賢明な選択である.
    3.partial関数設計
    def card7(rank,suit):
      from  functools import partial
      part_class = {
          1:partial(AceCard,'A'),
          11:partial(FaceCard,'J'),
          12:partial(FaceCard,'Q'),
          13:partial(FaceCard,'K')
      }.get(rank,partial(NumberCard,str(rank)))
    
      return part_class(suit)

    partial()関数を呼び出してpart_にコピーclassは、rankオブジェクトのチューブの関連付けを完了する、同様の方法でsuitオブジェクトを作成し、最終的なCardオブジェクトの作成を完了することができる.partial()関数の使用は関数時のプログラミングにおいてよく見られる.その際,オブジェクトではなく関数を用いる方法が考えられる.
    大体、partial()関数はオブジェクト向けのプログラミングではあまりよく使われていないので、構造関数の異なるバージョンを簡単に提供して同じことをすることができます.partial()関数はオブジェクトを構築する際のスムーズなインタフェースと似ている.
  • ファクトリモードのスムーズなAPI設計は、クラス内のメソッドを特定の順序で呼び出す必要がある場合がある.この順序呼び出しの方法はpartial()関数を作成する方法と非常に似ている.

  • スムーズインタフェース関数でself値を返すrankオブジェクトを設定し、花色クラスに転送してCardインスタンス/
    以下はCardファクトリのスムーズなインタフェースの定義であり、2つの関数を含み、順序に従って呼び出さなければならない.
    class CardFactory(object):
        def rank(self,rank):
            self.class_,self.rank_str = {
                1:(AceCard,'A'),
                11:(FaceCard,'J'),
                12:(FaceCard,'Q'),
                13:(FaceCard,'K')
            }.get(rank,(NumberCard,str(rank)))
        
        def suit(self,suit):
            return self.class_(self.rank_str,suit)

    まずrank()関数を用いてコンストラクション関数の状態を更新し、suit()関数によって最終的なCardオブジェクトを作成する.
    def A (rank):
    
        a,b ={                      #            .      . dict get  
            1: (AceCard, 'A'),
            11: (FaceCard, 'J'),
            12: (FaceCard, 'Q'),
            13: (FaceCard, 'K')
        }.get(rank, (NumberCard, str(rank)))
        return a,b #       tuple(),a    , b  '3'
    
    a = A(3)
    print(a)

    まずファクトリオブジェクトをインスタンス化し、次にCardインスタンスを作成します.これは使用されません.init__()Cardクラスの階層構造の役割は、呼び出し者がオブジェクトを作成する方法を変更する.
    各サブクラスで実装__init__()メソッド
    次のコードは、__をどのように表示するかを示しています.init__()方法はベースクラスカードで実現する過程に言及する.次に、サブクラスでベースクラスの実装を再利用することができる.
    
    class Card(object):
        def __init__(self, rank, suit, hard, soft):
            self.rank = rank
            self.suit = suit
            self.hard = hard
            self.soft = soft
    
    
    class NumberCard(Card):
        def __init__(self, rank, suit):
            super().__init__(str(rank), suit, rank, rank)
    
    
    class AceCard(Card):
        def __init__(self, rank, suit):
            super(AceCard, self).__init__("A", suit, 1, 11)
    
    
    class FaceCard(Card):
        def __init__(self, rank, suit):
            super(FaceCard, self).__init__({11: 'J',
                                            12: 'Q',
                                            13: 'K'}[rank], suit, 10, 10)
            
    
    def card10(rank,suit):
        if rank == 1:
            return AceCard(rank,suit)
        elif 2<= rank < 11:
            return NumberCard(rank,suit)
        elif 11<= rank <14:
            return FaceCard(rank,suit)
        
        else:
            raise  Exception('Rank out of range')

    ここではベースクラスの__init__を再構成する、それを複雑化するが、このようなトレードオフは正常である.
    ファクトリ関数パッケージの使用の複雑さ
       `__init__()`               ,       '     ' `__init__()`                .               ,           .
    
    

    単純なコンビネーションオブジェクト
    1つの組み合わせの対象を容器と呼ぶこともできる.
    ビジネスロジックが比較的単純な場合、なぜ新しいクラスを定義しますか?
    クラスの定義の利点の1つは、次のとおりです.
  • クラスはオブジェクトに簡単な、実現する必要のないインタフェースを提供する.

  • 集合クラスを設計します.通常、次の3つのポリシーがあります.
  • パッケージ:これは実際には既存の集合クラスに基づいて新しいクラスを定義し、外観モードの使用シーンに属する.
  • 拡張:この設計は既存の集合クラスを拡張するものであり、通常はサブクラスを定義する方式で実現される.
  • 作成:再設計.

  • 以上が対象設計の核心である.
    パッケージ集合クラス
    以下、内部集合のパッケージ設計を行う.
    import random
    class Deck(object):
       def __init__(self):
           self._cards = [card6(r+1,s) for r in range(13) for s in (Club,Diamond,Heart,Spade)]
           random.shuffle(self._cards)
       def pop(self):
           return self._cards.pop()
    
    d = Deck()
    
    hand = [d.pop(),d.pop()]

    一般に、外観モードまたはパッケージクラスを購入する方法は、下位オブジェクトに対応する関数のエージェント呼び出しにすぎない.
    class Desk3(list):
        def __init__(self, decks=1):
           super(Desk3, self).__init__()
           for i in range(decks):
               self.extend(card6(r + 1, s) for r in range(13) for s in (Club, Diamond, Heart, Spade))
               random.shuffle(self)
               burn = random.random(1,52)
               for i in range(burn):
                   self.pop()

    ここでは、ベースクラスの__init__()関数を用いて空の集合を作成し、self.extrend()を呼び出して複数のサブカードを発札機にロードする.
    複雑なコンビネーションオブジェクト
    トランプ戦略をシミュレートする
    class Hand:
        def __init__(self,dealer_card):
            self.dealer_card = dealer_card
            self.cards = []
            
        def hard_total(self):
            return sum(c.hard for c in self.cards)
        
        def soft_total(self):
            return sum(c.soft for c in self.cards)
    d = Deck()
    h = Hand(d.pop())
    h.cards.append(d.pop())
    h.cards.append(d.pop())
    

    1つずつ追加するのは大変不便です
    コンビネーションオブジェクトの初期化を完了__init__()の初期化方法は、もちろんこれが理想的な場合である完了したオブジェクトを返すべきである.これは、作成するオブジェクトの内部に集合が含まれている可能性があり、集合には他のオブジェクトが含まれているため、複雑さをもたらす.
    一般に、スムーズなインタフェースを用いて、集合にオブジェクトを追加する操作を完了するとともに、集合オブジェクトを構造関数として初期化を完了することが考えられる.例:
    class Hand2:
        def __init__(self, dealer_card, *cards):
            self.dealer_card = dealer_card
            self.cards = list(cards)
    
        def hard_total(self):
            return sum(c.hard for c in self.cards)
    
        def soft_total(self):
            return sum(c.soft for c in self.cards)
    
    d = Deck()
    h = Hand2(d.pop(),d.pop(),d.pop(),d.pop())
    print(h.cards)
    __init__メソッドを持たないステータスレスオブジェクト
    1つのポリシーオブジェクトはプラグインの形式で主オブジェクトに複合してアルゴリズムまたは論理を完成する.これは、プライマリオブジェクト内のデータである可能性があり、ポリシーオブジェクト自体はデータを携帯していない.通常、ポリシークラスはヘンメタ設計モードとともに使用する:ポリシーオブジェクトに内部記憶を避ける.必要な値はすべてポリシーオブジェクトのメソッドパラメータから入力.ポリシーオブジェクト自体は無状態である.一連の関数の集合と見なすことができる.
    ここでは、Playerのインスタンスにゲームを提供するクラスの選択モードを定義し、以下のポリシーには、トランプと注釈が含まれる.
    class GameStrategy:
        def insurnace(self, hand):
            return False
    
        def split(self, hand):
            return False
    
        def double(self, hand):
            return False
    
        def hit(self, hand):
            return False

    各関数は既存のHandオブジェクトに伝達する必要があり、関数論理に必要なデータは既存の利用可能な情報に基づいている.データは荘家とプレイヤーの手札から来ていることを意味する.
    その他のクラス定義
    プレイヤーにはトランプと賭けの2つの戦略がある.各Playerインスタンスのラウンドシミュレータは、複数回のインタラクションを行う.ここではこのシミュレータをTableと名付けます
    Tableクラスの役割は、Playerインスタンスに合わせて次のイベントを完了する必要があります.
  • プレイヤーは、トランプ戦略に基づいてトランプを初期化しなければならない.
  • その後プレイヤーは手札
  • を手に入れる
  • 以下にTableクラスにおける賭けとカードの論理処理に関するコードを示す.
    
    class Table:
        def __init__(self):
            #   52  
            self.deck = Deck()
    
        def place_bet(self, amount):
            print('Bet', amount)
    
        def get_hand(self):
            try:
                # self.hand = Hand2(d.pop(), d.pop(), d.pop())
                # self.hole_card = d.pop()             ,      
                self.hand = Hand2(self.deck.pop(), self.deck.pop(), self.deck.pop())
                self.hole_card = self.deck.pop()
            except IndexError:
                # Out of cards: need to shuffle
                self.deck = Deck()
                return self.get_hand()
            print('Deal', self.hand)
            return self.hand
    
        #      hand    ,      insure   。      。
        def can_insure(self, hand):
            return hand.dealer_card.insure
    
    class BettingStrategy:
        def bet(self):
            raise NotImplementedError('No bet method')
        
        def record_win(self):
            pass
        
        def record_lose(self):
            pass
        
    class Flat(BettingStrategy):
        def bet(self):
            return 1

    上のコードがまだ読めていないので、後でもう一度見に来なければなりません.
    マルチポリシーの__init__()メソッド
    class Hand4:
        def __init__(self, *args, **kwargs):
            print(len(args),args,kwargs)
            if len(args) == 1 and isinstance(args[0], Hand4):
                other = args[0]
                self.dealer_card = other.dealer_card
                self.cards = other.cards
    
            elif len(args) == 2 and isinstance(args[0], Hand4) and 'split' in kwargs:
                # Split an existing hand
                other, card = args
                self.dealer_card = other.dealer_card
                self.cards = [other.cards[kwargs['split']], card]
            elif len(args) == 3:
                # Bulid a fresh ,new hand
                dealer_card,*cards = args
                self.dealer_card = dealer_card
                self.cards = list(cards)
    
            else:
                raise TypeError('Invaild constructor args= {0!r} kw={1!r}'.format(args,kwargs))
    
        def __str__(self):
            return ','.join(map(str,self.cards))
    
    
    d = Deck()
    
    h = Hand4(d.pop(),d.pop(),d.pop())
    print(h)
    
    # s1 = Hand4(h,d.pop(),split = 0)
    # s2 = Hand4(h,d.pop(),split = 1)
    class Hand5:
        def __init__(self,dealer_card,*cards):
            self.dealer_card = dealer_card
            self.cards = list(cards)
    
        @staticmethod
        def freeze(other):
            hand = Hand5(other.dealer_card,*other.cards)
            return hand
    
        @staticmethod
        def split(other,card0,card1):
            hand0 = Hand5(other.dealer_card,other.cards[0],card0)
            hand1 = Hand5(other.dealer_card,other.cards[1],card1)
            return hand0,hand1
    
        def __str__(self):
            return ','.join(map(str,self.cards))
    
    d = Deck()
    
    h = Hand5(d.pop(),d.pop(),d.pop())
    s1,s2 = Hand5.split(h,d.pop(),d.pop())

    第1ラウンドが終了すると、dealerの手札が1枚、Playerの手札が2枚あり、手札の2枚が同じ場合、プレイヤーは分札を選択し、手の中の2枚を2組に分けてゲームを継続することができる.そしてトランプはPalyerの各グループに1枚のカードを送ります
    より多くの__init__()テクノロジー
    以下はPlayerクラスの定義です.初期化には2つのポリシーオブジェクトと1つのtableオブジェクトを使用します.