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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

990閲覧

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

mannah

総合スコア5

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/08/18 12:30

編集2020/08/18 12:46

・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)

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/08/18 12:40

>何故 data の方は 初期化しないか理解できません。 初期化以前に、dataは、インスタンス変数にもなっていません。 インスタンス変数にしていないこと、初期化しないこと、どちらを疑問に思っていますか?
sfdust

2020/08/18 12:44

動画のリンクは削除し、該当するコードを記載してください。
mannah

2020/08/18 12:44

インスタンス変数というのは、 a001 = Student("sato") の部分の "sato" のことでしょうか。 そうであれば、どちらも疑問です。 (例えば、a001 = Student("sato", data) のように、name 以外をインスタンス変数として設定しないのかがわかりません。 何故ここでは name のみが インスタンス変数として設定する方が好ましい?のでしょうか。
meg_

2020/08/18 12:58

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

2020/08/18 13:03

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

2020/08/18 15:08

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

回答2

0

ベストアンサー

元の回答

質問1

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

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

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

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

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

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

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

質問2

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

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

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

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

python

1class Student: 2 3 def __init__(self, name, data): 4 self.name = name 5 self.data = data 6 7 def calculate_avg(self): 8 sum = 0 9 10 # data の 中身である[70,65,50,90,30]を num で左から格納する 11 for num in self.data: 12 sum += num 13 14 avg =sum/len(self.data) 15 return avg 16 17 def judge(self): 18 if(self.calculate_avg() >= 60): 19 result = "passed" 20 else: 21 result = "failed" 22 return result 23 24a001 = Student("sato", [70,65,50,90,30]) 25 26print(a001.calculate_avg()) 27print(a001.name) 28print(a001.judge())

実行結果:

console

1$ python test.py 261.0 3sato 4passed

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

python

1a001 = Student("sato") 2data = [70,65,50,90,30] 3avg = a001.calculate_avg(data) 4judge_result = a001.judge(avg) 5 6print(avg) 7print(a001.name) 8print(judge_result)

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

python

1a001 = Student("sato", [70,65,50,90,30]) 2 3print(a001.calculate_avg()) 4print(a001.name) 5print(a001.judge())

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

追記

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

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

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

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

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

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

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

python

1class Student: 2 3 def __init__(self, name): 4 self.name = name 5 6a001 = Student() 7print(a001.name)

実行結果:

console

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

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

python

1class Student: 2 3 def __init__(self, name="Taro"): 4 self.name = name 5 6a001 = Student() 7print(a001.name)

実行結果:

console

1python test.py 2Taro

投稿2020/08/18 13:42

編集2020/09/09 13:55
y_shinoda

総合スコア3272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mannah

2020/09/09 12:58

すみません、返信遅くなってしまいました。 回答内容確認させていただきました。あと一点だけ確認させてください。 >状態を持つ必要があるかどうかで判断します 初期化というか、アトリビュートを定義するということは、状態を持つということです 今回の例では、生徒に点数を状態として持たせると、 次のように、クラスを呼び出している側のコードの変数を減らせます: …とありましたが、 アトリビュート定義(状態を持たせる)のと、初期化せず、外で変数を持たせるかどうかは、  実装する機能の仕様に合わせて、ソースコードがより簡潔に短くなる方をアトリビュートとして採用すべき、ということでしょうか。 また、「インスタンスごとに、アトリビュートを定義する必要がある」 との説明があったのですが、今回の場合、name と data のいずれかをアトリビュートとして定義しないと、そもそもインスタンス化ができない、という理解であってますでしょうか。
y_shinoda

2020/09/09 13:55

回答に追記しました
mannah

2020/09/09 14:55

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

0

>a001 = Student("sato", data)

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

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

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

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

と考えられませんか。

投稿2020/08/18 12:53

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mannah

2020/08/18 13:01

tajin さん 回答確認ました。 name は生まれた時に決まっている、data (試験の成績かな)は、半期ごとの中間テストのたびに変化する ということを判断基準に、インスタンス変数を設定している、ということですね。 今回の考え方としては、 今回のこの クラス Student は、 あくまで一人ひとりの 得点の 平均点を算出し、合格/不合格 を求めたいから、 インスタンスとして 持っておくべき値?が名前ということなのでしょうか…? というか、何故 変化しない値(今回は name )がインスタンス変数としてふさわしいのでしょうか。 data も、その人が今回の judge 判定となる対象のテスト結果、という意味では、 [70,65,50,90,30]が固定なのでは…と思ってしまいました…。
退会済みユーザー

退会済みユーザー

2020/08/18 13:28

この例題のStudentについては、dataをインスタンス変数にするのも、しないのも、どちらもアリで 正解はないと思います。 dataはここではcalculate_avgの入力としてしか使われていないので、 dataは読み手次第で、どんな意味にもなりえます。 mannahさんが、新たにクラスを設計するときに、何をインスタンス変数とするべきか、 都度、考えていくしかないのではないでしょうか。
mannah

2020/08/18 13:40

tajin さん ありがとうございます。どちらもアリなのですね…そのどちらにするのがベストなのかが判断できず、悩んでいるところでした…。 参考として確認させてもらいたいのですが、tajin さんがこのstudentクラスを作成する時には、どこまでをインスタンス変数として設定しますか? また、理由も含めて教えていただけると幸いです。 何度読み返してもインスタンス変数の設定基準が考えられず…。 わかりにくい質問してしまって申し訳ありません。
退会済みユーザー

退会済みユーザー

2020/08/18 14:16

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

2020/09/09 13:07

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問