質問: 参考書内で”戦争”と呼ばれるゲームのコードを作っていた際の質問です。 該当ページ、辞書として用いている参考書、ネットの情報を参照しても不明点が解決せず、これ以上考えるのはあまりよくないと思い質問させていただきます。 初歩的な質問だとは思いますが、これを機にクラスへの理解を深めたいです。 コードが長いため、下に掲載します。 1Cardクラスのスイート、2・3番目のメソッド `__lt__`,`__gt__`の引数である`c2`がどこでこのメソッドに渡されているのかわかりません。 なので、ここのif文にあるc2.valueがどこから引っ張ってこられているのか全く分かりません。 2,3(おそらく同類の質問) Gameクラスのスイート、4番目のメソッド whileループの中2番目のif文の`self.p1.wins`の参照の仕方について ☆☆☆を参照する際にwinsにselfをつけなくてもいいのですか? 同クラス、5番目のメソッド ここでの2つのif文returnに渡す変数はselfをつけてもつけなくてもよいのですか? 書いているようにselfつけてもつけなくても正常に動きはしました。 参考書では、参照する際にはselfをつけるように記載されていたので少々混乱しています。 コードです。 ``` class Card: suits=["spades","hearts","diamonds","clubs"] values=[None,None, "2","3","4","5","6","7","8","9", "10","Jack","Queen","King","Ace"] def __init__(self,v,s): """スート・マークはともにint型オブジェクトで扱います""" self.value=v self.suit=s def __lt__(self,c2): #__lt__は比較用の特殊メソッドです(より小さい) #c2がどこで作られるオブジェクトなのかわかってません。 #でも、__lt__ or __gt__メソッドが呼ばれればその時の引数に渡せばいい。え、でもそれもどこ?ww if self.valuec2.value: return True if self.value==c2.suit: return True if self.suit>c2.suit: return True else: return False def __repr__(self): v=self.values[self.value]+" of "+self.suits[self.suit] return v from random import shuffle #意味をきちんと言えるようにしましょう。 class Deck: def __init__(self): self.cards=[] for i in range(2,15): #トランプの52枚のカードを用意しています。 for j in range(4): self.cards.append(Card(i,j)) shuffle(self.cards) def rm_card(self): if len(self.cards)==0: #カードの枚数が0になると終わりです。 return return self.cards.pop() #引くカードの被りを避けています。 """ deck=Deck() for card in deck.cards: #参照の仕方をきちんと覚えましょう。 print(card) このコードによりトランプが正確に出力されるか確認しました。 また、ここまでのエラーに直結する要素は全て解決されています。 """ class Player: #後で使うための下準備です。 def __init__(self,name): self.wins=0 #☆☆☆ self.card=None self.name=name class Game: #これ、”ここ”でDeck呼び出してるけど、継承した時との違いは? def __init__(self): name1=input("プレイヤー1の名前 ") name2=input("プレイヤー2の名前 ") self.deck=Deck() #ここ #上はDeckクラスのオブジェクトとしてカードをdeckのセルフ変数に参照しています。 self.p1=Player(name1) self.p2=Player(name2) def wins(self,winner): w="このラウンドは{}が勝ちました" w=w.format(winner) #winsメソッドの引数winnerが上の{}に追加されます。 print(w) def draw(self,p1n,p1c,p2n,p2c): #それぞれのプレイヤーが引いたカードをコールします。 d="{}は{}、{}は{}を引きました。" d=d.format(p1n,p1c,p2n,p2c) print(d) def play_game(self): cards=self.deck.cards #Deckクラスのself.deckオブジェクトを引数としてDeckクラス内のcardsメソッドに渡します。 print("Let's begin the game called war!") while len(cards)>=2: m="qで終了、それ以外のキーでPlay:" response=input(m) if response=="q": break p1c=self.deck.rm_card() p2c=self.deck.rm_card() p1n=self.p1.name p2n=self.p2.name self.draw(p1n,p1c,p2n,p2c) if p1c>p2c: self.p1.wins+=1 #これ、☆☆☆を参照しているのだろうけどwinsにselfはいらない? self.wins(self.p1.name) else: self.p2.wins+=1 self.wins(self.p2.name) win=self.winner(self.p1,self.p2) print("ゲーム終了、{}の勝利です!".format(win)) def winner(self,p1,p2): if p1.wins>p2.wins: return self.p1.name #元はp1.nameだったけど、self変数にしなくていいのか迷ったのでいったんself変数で書いてます。 if p1.wins
回答: ### 1 `__lt__(self, c2)` の `c2` とは何か? `<` で比較するときの右側の引数です。こちらの別質問をご覧ください: 「クラスの関数で、self 以外の変数が何なのか分からない」 ### 2 `self.p1.wins += 1` の `wins` に `self` はつけなくて良い? つけません。 `self` は自分自身のことを示す特別なオブジェクトなのでした。また、`self.p1` もオブジェクトであり、`Game` クラスのインスタンス変数 `p1` のことを指しています。 つまりこの行では「`Game` クラスのインスタンス変数 `p1`」のインスタンス変数 `wins` を操作しようとしているのです。`self.p1` の時点でどのオブジェクトの `wins` を操作しようとしているのか明らかです。 また、`self` という名前は同じですが、`Game` クラスのメソッドの中で使われる `self` は `Game` クラスのオブジェクトそのものを指しており、`Player` クラスのオブジェクトを指しているわけではないことにも注意してください。 ### 3 関数 `winner(self, p1, p2)` において `self.p1` と `p1` に差はある? 少なくとも `self.p1` と `p1` に差はあります。 `self.p1` は自分自身がインスタンス変数として持っている `p1` を指す一方、`p1` は関数 `winner` の引数として与えられた `p1` を指します。 「`self` をつけてもつけなくても同じように動作した」とのことですが、これは `play_game()` 関数の中で `winner` 関数を呼び出す際に以下のようにしているからです。 ``` win = self.winner(self.p1, self.p2) ``` 上のように使う限りは、`p1` と `self.p1` が一致するため、`self` があってもなくても同じ動作になります。(蛇足: このような使い方しかしないのであれば、`winner` 関数の引数 `p1`, `p2` は不要だと思われます。書籍中の別の箇所で違う使い方をするのかもしれません。)