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

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

ただいまの
回答率

87.91%

コンストラクタの初期化メソッドとについて教えてください。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 449

score 5

・Student クラス初期化メソッドについて

下記ソースのクラスについて質問です。

質問1
このクラス Student を書き始めた時に、「今回は、変数として、name(生徒名)、と data(平均点を算出する元データ)、の二つが必要だから、どちらも 初期化メソッドとして記載して、初期化しておこう。と思ったのですが、解説を見ると data の方は初期化しておらず。

クラス内で使われる アトリビュート(変数)はインスタンス事に必要と聞いていたので、その不便さを解消するためにコンストラクタを利用する理解だったので、 何故 data の方は 初期化しないか理解できません。何故ここでは name のみを初期化しているのでしょうか。

質問2
みなさんは自分でクラスを作成する際、どういった判断基準で、初期化する/しないを分けているのでしょうか。(いつもこのクラスの外に記載する/しないで間違えてしまい、途中でソースがかけなくなります。)

class Student:

    def __init__(self, name):
        self.name = name

    def calculate_avg(self, data):
        sum = 0

        # data の 中身である[70,65,50,90,30]を num で左から格納する
        for num in data:
            sum += num

        avg =sum/len(data)
        return avg

    def judge(self, avg):
        if(avg >= 60):
            result = "passed"
        else:
            result = "failed"
        return result

a001 = Student("sato")
data = [70,65,50,90,30]
avg = a001.calculate_avg(data)
judge_result = a001.judge(avg)

print(avg)
print(a001.name)
print(judge_result)


以上、よろしくお願いします。

  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • meg_

    2020/08/18 21:58

    動画(見てません)では練習(勉強)のためにクラスの色々な使い方を提示されてるのではないでしょうか?実際には用途によってインスタンス作成時に代入するか、後で代入するか選ぶかと思います。

    キャンセル

  • mannah

    2020/08/18 22:03

    meg さん
    ありがとうございます。
    そうなのですが、実際に今回練習でこの例題を解く際に、私は初めに
    a001 = Student("sato", data)
    と記載するのかな、と思ってつまずいたので、おそらく data はインスタンス変数として設定しないのが自然なのかな、と感じたのですが、理由?というか "sato" のみの方が都合が良い理由が理解できませんでした。

    キャンセル

  • meg_

    2020/08/19 00:08

    動画を見ました。
    > そうなのですが、実際に今回練習でこの例題を解く際に、私は初めに
    > a001 = Student("sato", data)
    > と記載するのかな、と思ってつまずいたので
    実践例は例題をベースにしているので、逆に何故例題と違う方法を取ろうとしたのか?の方が疑問に思います。練習なので素直に解けば良いと思います。
    先生のやり方が良くないと思うのであれば独自の方法で実装されても良いと思います。
    ※どうしても疑問に思うのであればご本人に質問されるのがベストだと思います。

    キャンセル

回答 2

checkベストアンサー

0

元の回答

質問1

何故 data の方は 初期化しないか理解できません。
何故ここでは name のみを初期化しているのでしょうか。

質問のコードの引用元:
(159) Python超入門コース 合併版|Pythonの超基本的な部分をたった1時間で学べます【プログラミング初心者向け入門講座】 - YouTube

ざっと見た感じ特に理由は述べられていなかったので
製作者のみ知るところですが、
予想としては、これは「超入門コース」であるためと思われます

入門者に教えるためには、難しいことを覆い隠して
順序立てて教える必要があります

いきなり難しいことを教えても、基礎がなければ理解することができないこともあるからです

ここでは設計が洗練されていることを犠牲にしてでも
引数を与えることができることを教える意図があったのではないかと思われます

設計としては data もアトリビュートとして持たせる設計の方が良いかもしれません

質問2

みなさんは自分でクラスを作成する際、
どういった判断基準で、初期化する/しないを分けているのでしょうか。

状態を持つ必要があるかどうかで判断します

初期化というか、アトリビュートを定義するということは、状態を持つということです

今回の例では、生徒に点数を状態として持たせると、
次のように、クラスを呼び出している側のコードの変数を減らせます:

class Student:

    def __init__(self, name, data):
        self.name = name
        self.data = data

    def calculate_avg(self):
        sum = 0

        # data の 中身である[70,65,50,90,30]を num で左から格納する
        for num in self.data:
            sum += num

        avg =sum/len(self.data)
        return avg

    def judge(self):
        if(self.calculate_avg() >= 60):
            result = "passed"
        else:
            result = "failed"
        return result

a001 = Student("sato", [70,65,50,90,30])

print(a001.calculate_avg())
print(a001.name)
print(a001.judge())

実行結果:

$ python test.py
61.0
sato
passed

リンク先の例のプログラムでは、
処理が 1 回で終わっているのでさほど不便を感じなかったかもしれませんが、
少なくとも、変数が散らかっています:

a001 = Student("sato")
data = [70,65,50,90,30]
avg = a001.calculate_avg(data)
judge_result = a001.judge(avg)

print(avg)
print(a001.name)
print(judge_result)

もし、クラスが状態を持ってくれていれば、次のようにスッキリします:

a001 = Student("sato", [70,65,50,90,30])

print(a001.calculate_avg())
print(a001.name)
print(a001.judge())

これは、クラスが点数を状態としてを持ったので、
クラスの外で変数として状態を持つ必要がなくなったためです

追記

アトリビュート定義(状態を持たせる)のと、初期化せず、外で変数を持たせるかどうかは、
実装する機能の仕様に合わせて、
ソースコードがより簡潔に短くなる方をアトリビュートとして採用すべき、ということでしょうか。

回答者によって見解が分かれるかもしれませんが、個人的には、ほぼ、その認識でよいと思います

設計としてはアトリビュートを定義する方が正しい場合でも、
ごくまれにですが、余計にコードが煩雑になる場合もあります
そのような場合はソースコードが簡潔に短くなる方の設計を採用することもあります

「インスタンスごとに、アトリビュートを定義する必要がある」
との説明があったのですが、今回の場合、
name と data のいずれかをアトリビュートとして定義しないと、
そもそもインスタンス化ができない、という理解であってますでしょうか。

コンストラクターの定義によります

今回のコードはコンストラクター内でアトリビュートを定義しています
しかし、そのコンストラクターに、アトリビュートの値として使われる引数を渡さなかった場合、
コンストラクターの呼び出しでエラーが発生します

例えば次のような場合はインスタンス化できずエラーとなります:

class Student:

    def __init__(self, name):
        self.name = name

a001 = Student()
print(a001.name)

実行結果:

$  python test.py 
Traceback (most recent call last):
  File "test.py", line 6, in <module>
    a001 = Student()
TypeError: __init__() missing 1 required positional argument: 'name'

次のように、コンストラクターの引数に初期値を定義しておくと、エラーは発生しません:

class Student:

    def __init__(self, name="Taro"):
        self.name = name

a001 = Student()
print(a001.name)

実行結果:

python test.py 
Taro

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/09/09 21:58

    すみません、返信遅くなってしまいました。
    回答内容確認させていただきました。あと一点だけ確認させてください。

    >状態を持つ必要があるかどうかで判断します
    初期化というか、アトリビュートを定義するということは、状態を持つということです
    今回の例では、生徒に点数を状態として持たせると、
    次のように、クラスを呼び出している側のコードの変数を減らせます:

    …とありましたが、
    アトリビュート定義(状態を持たせる)のと、初期化せず、外で変数を持たせるかどうかは、
     実装する機能の仕様に合わせて、ソースコードがより簡潔に短くなる方をアトリビュートとして採用すべき、ということでしょうか。

    また、「インスタンスごとに、アトリビュートを定義する必要がある」
    との説明があったのですが、今回の場合、name と data のいずれかをアトリビュートとして定義しないと、そもそもインスタンス化ができない、という理解であってますでしょうか。

    キャンセル

  • 2020/09/09 22:55

    回答に追記しました

    キャンセル

  • 2020/09/09 23:55

    ありがとうございました。
    なんとなくではありますが、アトリビュート定義をするしないの基準が少し理解できた気がします。
    今後もここでの回答参考にさせていただきます…!

    キャンセル

0

>a001 = Student("sato", data)

なるほど。。。nameとdata  の両方がインスタンス変数となるほうが自然に思えたのですね。

しかしこれはもう、Studentクラスの設計というか、仕様次第というよりほか、ないかなと思います。

たとえば、こんな説明はどうでしょうか。

・name は生まれた時に決まっている ⇒ インスタンス化するときに决めてしまおう
・data (試験の成績かな)は、半期ごとの中間テストのたびに変化する ⇒ インスタンス変数ではなく、都度、計算しよう

と考えられませんか。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/08/18 22:40

    tajin さん
    ありがとうございます。どちらもアリなのですね…そのどちらにするのがベストなのかが判断できず、悩んでいるところでした…。

    参考として確認させてもらいたいのですが、tajin さんがこのstudentクラスを作成する時には、どこまでをインスタンス変数として設定しますか?
    また、理由も含めて教えていただけると幸いです。

    何度読み返してもインスタンス変数の設定基準が考えられず…。
    わかりにくい質問してしまって申し訳ありません。

    キャンセル

  • 2020/08/18 23:16

    この例の場合、Studentにとって、dataは、calculate_avgの入力としてしか、
    利用されていません。
    なので、インスタンス変数にする利点が見えません。
    それはこのコードが小さすぎるからかな。

    ・インスタンス変数にする=状態をもたせる(腹にかかえる)、ですので、
    インスタンス(今回の場合はa001)と、dataとをバラバラにしないメリットが見えたら、
    (たとえばですが、a001を呼び出し元(といっても今回は、a001は一番外側で生成されているので呼び出し元がないけど)に返すような処理で、かつ、再び、そこでもdataを利用して何かを計算する、など)
    インスタンスにします。

    キャンセル

  • 2020/09/09 22:07

    返信遅くなってしまい申し訳ありませんでした。
    今回だと、 a001は固定(名前なので)だから状態を持たせてしまってOKな反面、
    data は色々な点数を持たせて passed failed を切り分ける場合は状態として持たせないほうがよいかも…という感じでしょうか。

    >(たとえばですが、a001を呼び出し元(といっても今回は、a001は一番外側で生成されているので呼び出し元がないけど)に返すような処理で、かつ、再び、そこでもdataを利用して何かを計算する、など)インスタンスにします。
    すみません、この例えばの場合の例の具体的な例を挙げてもらえたりしないでしょうか…ここのバラバラにしないメリットについて、あと一歩くらいで理解しできそうです。
    「dataを利用して何かを計算する」のところなどの具体的なイメージが中々できず…
    説明いただけているのに、心苦しいこと言ってしまい申し訳ありません…。

    キャンセル

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

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

関連した質問

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