49071


Pythonで勉強をかねて戦争ゲームを制作しているのですが、いまいち読めずに苦戦しています。  
`def __gt__(self, c2)`このコードが`de f__gt__(self, c1, c2)`になってないのが気になります。  
`if p1c > p2c:`が実行される時に`def __gt__(self,
c2)`のメソッドが実行されるのかなとは思いますが（もしかしたら違うのかも）なぜ`c1`は書かれていないのでしょうか？

[code]

    from random import shuffle
    
    class Card(object):
        """docstring for 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):
            self.value = v
            self.suit = s
    
        def __It__(self, c2):
            if self.value < c2.value:
                return True
            if self.value == c2.value:
                if self.suit < c2.suit:
                    return True
                else:
                    return False
    
        def __gt__(self, c2):
            if self.value > c2.value:
                return True
            if self.value == c2.value:
                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
    
    # ここでトランプを生成
    # デッキから一枚カードを取り出すメソッドもある！
    class Deck:
        def __init__(self):
            self.cards = []
            for i in range(2, 15):
                for j in range(4):
                    self.cards.append(Card(i, j))
            shuffle(self.cards)
            print(self.cards)
    
        def rm_card(self):
            if len(self.cards) == 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
    
    # Gameクラスがスタート
    # 次にデッキクラス
    class Game:
        def __init__(self):
            # プレーヤー１名前と表示されてその後ろに名前を入力
            name1 = input('プレーヤー１名前')
            name2 = input('プレーヤー２名前')
            self.deck = Deck()
            self.p1 = Player(name1)
            self.p2 = Player(name2)
    
        def wins(self, winner):
            w = 'このラウンドは{}が勝ちました'
            w = w.format(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
            print('戦争を始めます')
            # デッキが2枚以下になるまでループ
            while len(cards) >= 2:
                m = 'qで終了、それ以外のキーでplay:'
                response = input(m)
                if response == 'q':
                    break
                p1c = self.deck.rm_card()
                print(self.deck.cards)
                p2c = self.deck.rm_card()
                print(self.deck.cards)
                p1n = self.p1.name
                p2n = self.p2.name
                #自動で引かれたカードが何か表示
                self.draw(p1n, p1c, p2n, p2c)
                #どっちのカードが強いか比較して処理する。
                if p1c > p2c:
                    # playerクラスのwinに値を追加
                    self.p1.wins += 1
                    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 p1.name
            if p1.wins < p2.wins:
                return p2.name
            return '引き分け!'
    
    game = Game()
    game.play_game()
    
[/code]

**追記**  
selfがいまいちわかっていないと思うのですが、以下のサイトで  
<https://www.sejuku.net/blog/64106>

このような記載がありました。 **selfはインスタンス自身を示すものなので、呼び出す側は引数として値を入れない事です。**
これは__init__の特殊メソッドを使う時、限定ですか？

**追記2**

なんども追加の質問申し訳ありません。

**Cardクラスは自分自身が何なのか分からない状態なので、第一引数(self)も渡す必要があります。**  
このように記載されていたのですが、これは`class Card(object):`のように書いたから第一引数が必要という意味でしょうか？

多分こういうこと  
第一引数にはclassの名前が入る。

[code]

    class Boku(object):
        # これはクラス変数
        subject = "ぼくは"
        name = "ドラえもん"
    
        def __init__(self, nickname):
            self.nickname = nickname # これはインスタンス変数
            print(self.__class__.__name__)
    
    wataru = Boku('wakasu')
    
    実行結果:Boku
    
[/code]

**インスタンス（クラスからできたもの）のメソッドを呼び出すと、第一引数は自動的にそのインスタンス自身になる。**  
インスタンスの意味をしっかり把握できてなくて分からないのですが（[サイト](https://wa3.i-3-i.info/word1118.html)で確認はしました。）

c2はその後にインスタンスになるのでしょうか？


CC BY-SA 4.0
2018-10-08T15:33:53.960
49060
2018-10-13T10:39:02.827
2018-10-13T10:39:02.827
22565
22565
question
python python3
特殊メソッド __gt__ の引数が self の他に一つしか無い理由


> if `p1c > p2c:` が実行される時に `def __gt__(self, c2)`
> のメソッドが実行されるのかなとは思いますが（もしかしたら違うのかも）

合っています。

> なぜc1は書かれていないのでしょうか？

この場合、`>` 記号の左にある `p1c` が `__gt__` の引数 `self` になるからです。

* * *

ちょっと説明のために、あまり実践では使わない別の書き方を紹介します。

`p1c > p2c` は、以下のように別の書き方でも同じ動作をします。

[code]

    p1c.__gt__(p2c)   # p1c > p2c と同じ
    
[/code]

これはp1cの特殊メソッドを普通のメソッドのように呼び出すやりかたです。  
言い換えると、 `p1c > p2c`
のようにPythonコードを書いたときに、Python内部ではこの呼び出し方をしていると言えます。なぜ2つの使い方があるかというと、 `p1c > p2c`
と書いた方が人間が分かりやすいからです。でも `def >(self, other):`
のようには書けないので（Pythonを作った人がそういう書き方を選ばなかったので）、大小比較の動作を実装するには `def __gt__(self,
other):` のように書きます。

また、さらに別の書き方でも同じ動作になります。

[code]

    Card.__gt__(p1c, p2c)   # p1c > p2c と同じ
    
[/code]

これは、 `Card` クラスのメソッドを直接使っていて、この場合第一引数の `p1c`
はメソッド定義の最初の引数(self)に渡されます。`p1c.__gt__(p2c)`
の場合は、`Card`クラスのインスタンス`p1c`が自分自身だと分かっているので、各メソッドの第一引数(self)には自動的に`p1c`が渡されます。上記のように、`p1c`インスタンスのメソッドではなく`Card`クラスのメソッドを直接呼び出した場合、Cardクラスは自分自身が何なのか分からない状態なので、第一引数(self)も渡す必要があります。これは特殊メソッド以外でも同様です。

* * *

まとめると、以下の様になります

  * インスタンスのメソッドを呼び出すと、第一引数は自動的にそのインスタンス自身になる（という言語仕様）ので、呼び出し側は(selfを除く)第2引数以降だけを渡します。
  * クラスのメソッドを呼び出すと、主体となるインスタンスが不明なので、呼び出し側は(selfを含む)第一引数から渡す必要があります。
  * 特殊メソッドは、`c1 < c2` のような分かりやすい使い方を維持したまま、動作をカスタマイズしたいときに使います（この場合は大小比較のカスタマイズ）。


CC BY-SA 4.0
2018-10-09T00:02:15.120
49071
2018-10-09T00:02:15.120
806
49060
answer


`__gt__()`に関しては優れた回答が既にありますので、追記部分の`self`についてのみお答えします。

Pythonにおいて`self`はキーワードでも何でも無く、つまり、特別な意味はまったく無く、ただの仮引数の一つです。慣習としてインスタンスメソッド呼び出しとなるようなメソッドの第一引数(インスタンスメソッドでは第一引数がインスタンス自身になる)では`self`と名付けているだけになります。`def
__gt__(c1, c2)`として、`self`の部分を`c1`に置き換えても同じように動作します。

[code]

    class Game:
        // ...略...
        def __gt__(c1, c2):
            if c1.value > c2.value:
                return True
            if c1.value == c2.value:
                if c1.suit > c2.suit:
                    return True
                else:
                    return False
    
[/code]

これは`__init__`を含む全てのインスタンスメソッドに言えることです。下記の公式ドキュメントも参考にしてください。  
[9.4. いろいろな注意点 - 9. クラス — Python 3.6.5
ドキュメント](https://docs.python.jp/3/tutorial/classes.html#random-remarks)

> よく、メソッドの最初の引数を `self` と呼びます。この名前付けは単なる慣習でしかありません。`self` という名前は、 Python
> では何ら特殊な意味を持ちません。とはいえ、この慣行に従わないと、コードは他の Python プログラマにとってやや読みにくいものとなります。また、
> _クラスブラウザ (class browser)_ プログラムがこの慣行をあてにして書かれているかもしれません。


CC BY-SA 4.0
2018-10-09T13:54:18.910
49114
2018-10-09T13:54:18.910
7347
49060
answer