質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

pythonのクラス継承 selfやlist、インステンスとは

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 3,690

torano

score 91

プログラミング始めたばっかの初心者です。
以下のコードでわからない点がありました。

class Deck(list):
    def __init__(self):
        list.__init__(self)
    def make_card(self, name, power):
        return {name:power}
    def add_card(self, name, power):
        self.append(self.make_card(name, power) )
    def print_deck(self):
        print "all card num:", len(self)
        for card in self:
            print card

if __name__ == "__main__":
    t = Deck()
    for i in xrange(1, 10):
        t.add_card("card no."+str(i), i * 4 + 10)
    t.print_deck()


疑問点は3つです。公式ドキュメントを見てみたりしたのですが難しくてあまり理解できませんでした。初心者にもわかるように教えてもらえないでしょうか。よろしくお願いします。

1、継承元がlistだと思うのですが、具体的に定義されてないですし、print listなどとしても表示されないですし、これはなんなのでしょうか?変数ではないんですか?

2、selfってクラス関数の第一引数だからインスタンスを代入されたtの事だと思うのですが、7、10行目を見るとどうやらリストになっているみたいでよくわかりません。インスタンスの定義もそもそもよくわかっていないです。

3、上記のコードの7、9、10行目のselfをlistに置き換えても失敗するのはどうしてでしょう?下記のコードではうまくいっていますが違いがわかりません。また逆に下記のコードでlistをselfに置き換えてもうまくいきません。

# -*- coding: utf-8 -*- 

class TestExtends(list):

    def __init__(self):
        list.__init__(self)

    def append(self,value):
        list.append(self,value)
        print u"値が追加されました:" + str(value)


if __name__ == "__main__":

    test = TestExtends()
    test.append("python")
    test.append("-")
    test.append("izm")

    print "==============="

    for i in test:
        print i
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

質問3は TestExtends のケースと似ているのになぜ違うかということかと思います。

Deckクラスの append は継承しているlist のappend を呼び出す必要があります。
Deckクラスには独自の append はないので、 self.append で list のappend が呼ばれます。

これに対し、TestExtends クラスには 継承しているlist のappend とは別の TestExtends 独自の appned が定義されているため、ここで
    def append(self,value):
        self.append(value)
としてしまうと、自分(TestExtends)のappendが呼び出されておかしなことになってしまいます。

Deckクラスの add_card を list を使って書き換えるなら以下のようになります。
    def add_card(self, name, power):
        list.append(self,self.make_card(name, power) )

また、TestExtends クラスを self を使って書き換えるなら以下のようになります。
上で説明したように append の名前が重なっているため append を myappend として

    def myappend(self,value):
        self.append(value)

呼び出す方は
    test.myappend("python")
のような形になります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/01/03 13:18

    list.append(self,self.make_card(name, power) )はselfに要素を追加しているということですか?

    キャンセル

  • 2016/01/03 15:54

    そうです。
    list.append(self,xx .. は self.append(xx... と同じなので。
    この部分は9,10行目の話とは違って、tanaga さんが「メソッドオブジェクト」で説明されている話です。

    キャンセル

  • 2016/01/03 18:00

    なるほど!理解できました、ありがとうございます

    キャンセル

+1

予約語以外は変数です。listも(ビルトイン)変数です。
問題は、変数は何でも入るので、今その変数に何が入っているのかを把握することが重要です。

1、継承元がlistだと思うのですが、... 変数ではないんですか?

変数ですが、中に入っている型が重要です。listは標準でクラスが入っている変数ですね。

2、selfってクラス関数の第一引数だからインスタンスを代入されたtの事だと思うのですが

その通りです

7、10行目を見るとどうやらリストになっているみたいでよくわかりません。

クラスを"棒のハンコ"、インスタンスをそれを"紙に押したハンコ"と思ってください。
どちらも「ハンコ」なのでわかりづらいですね。listも同じです。

3、上記のコードの7、9、10行目のselfをlistに置き換えても失敗するのはどうしてでしょう?

「"紙に押したハンコ"を"棒のハンコ"に置き換えたら動きません」当たり前ですね。

下記のコードではうまくいっていますが違いがありません。また逆に下記のコードでlistをselfに置き換えてもうまくいきません。

ここがPythonのややこしいところです。以下の文章が参考になるでしょう。
Pythonは初期はクラスを持っておらず、後から追加した際にこのような仕様で「吸収」した経緯があります。

9.3.4. メソッドオブジェクト

x = MyClass() ... (中略) ... x.f() という呼び出しは、 MyClass.f(x) と厳密に等価なものです。

ただし、実際には「MyClass.f(x)」ではなく「x.f()」のほうが良いでしょう。
なぜなら、後からMyClassではなくYourClassに変えたくなった時に、最初の1箇所だけ変えれば良いためです(別のやり方だと2箇所変えなくてはならないし、YourClassがMyClassを継承している場合は忘れる可能性が非常に高いし、忘れたことに気づきにくい)。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/01/02 18:50 編集

    x = MyClass() ... (中略) ... x.f() という呼び出しは、 MyClass.f(x) と厳密に等価なものです。
    とありますが、この文のxをself、MyClassをlistに置き換えたもの(つまりself.f()とlist.f(self)が同値)という解釈でおkでしょうか?

    キャンセル

  • 2016/01/02 19:29

    もう一つ、listがリストクラス、selfがインスタンスだという認識だったのですが、もしかしてselfはリストクラスでもあるんですか?例えば
    x=[]
    x.append(3)
    とするとリストクラスxに要素3が追加されますが、最初に紹介したコードのDeckクラスでも self.append(self.make_card(name, power) )と同じようになってますよね。(逆にlistではこれと同じように書くとうまくいきません)
    理解できてきたと思ったらまたこんがらがってきました...

    キャンセル

  • 2016/01/02 21:14


    > listがリストクラス、selfがインスタンスだという認識だったのですが

    あっていますね。listがリストクラス、selfがリストインスタンスですね。

    もしJavaをご存知なら、もう少し話は簡単です。
    Javaのインスタンスメソッド内で自分自身を参照するときは、thisを使います。thisはシステムが用意してくれる変数です。
    Pythonにはthisがありません。これは、Pythonの初期の設計にはクラスの機能が無かったからです。Pythonの作者はPythonに後からクラスの機能を追加するときに、thisをシステムで用意せず、インスタンスメソッドの第1引数に自分自身(this相当)を用意することにし(てなんとかごまかし)ました。
    第1引数の名前はなんでもいいのですが、多くの人がselfにしているのでそのようにしましょう。

    上記の経緯から、インスタンスメソッドを呼び出す方法が2種類ほどできてしまったわけです。この説明でわからない場合は、少し間を置いて見なおすか、もっとじっくり公式文章を読むべきです。

    キャンセル

  • 2016/01/02 22:58

    コーディングはpythonが初めてで。。。
    じっくりドキュメントを見直してみます
    ありがとうございました

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る