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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

3582閲覧

インスタンス変数の定義にif文を入れるとプログラムが終了しない

pupperccino

総合スコア17

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2019/02/21 16:17

プログラミング経験が浅いので、専門用語に間違いがあったりコードが稚拙であったりするかもしれませんがご容赦ください。

前提

以下の課題を解いています。is_alive変数を持たせる所で何か変なことになっている可能性が高いのですが、何がダメでどう直せば正しく動くのかが分かりません。
0. Warrior型を作成する。
Warrior型のオブジェクトはhealth, attackという2つの変数を持ち、それぞれ50, 5という数である。またis_aliveという変数も持ち、health > 0ならTrue、そうでなければFalseである。
0. Knight型を作成する。
Knight型はWarrior型の子クラスであり、Warrior型と同様にhealth, attack, is_aliveを持つ。attackが7である点以外はWarrior型と同じ。
0. fight(unit1, unit2)という関数を作成する。
unit1がunit2に攻撃し、unit2.healthがunit1.attackだけ減る。もしunit2が生きていれば(unit2.is_alive == Trueならば)unit2がunit1に攻撃し、unit1.healthがunit2.attackだけ減る。
これをどちらかのhealthが0以下になるまで繰り返す。このときunit1.is_alive == Trueなら関数fightはTureを、そうでなければFalseを返す。

発生している問題・エラーメッセージ

プログラムをコマンドプロンプトから実行したところ、終了しませんでした。Ctrl+Cで中止させたところ次のメッセージが表示されました。

Traceback (most recent call last): File "test.py", line 37, in <module> print(fight(chuck, bruce)) File "test.py", line 22, in fight unit_1.health -= unit_2.attack

該当のソースコード

Python

1class Warrior: 2 def __init__(self): 3 self.health = 50 4 self.attack = 5 5 6 # ここが怪しい 7 if self.health > 0: 8 self.is_alive = True 9 else: 10 self.is_alive = False 11 12 13class Knight(Warrior): 14 def __init__(self): 15 super().__init__() 16 self.attack = 7 17 18 19def fight(unit_1, unit_2): 20 while unit_1.is_alive == True and unit_2.is_alive == True: 21 unit_2.health -= unit_1.attack 22 if unit_2.is_alive == True: 23 unit_1.health -= unit_2.attack 24 25 if unit_1.is_alive == True: 26 return True 27 else: 28 return False 29 30 31# ここから下はコードが正しい結果を返すか確かめるためのものなので、課題本体は以上で終わりです。 32chuck = Warrior() 33bruce = Warrior() 34carl = Knight() 35dave = Warrior() 36mark = Warrior() 37 38 39print(fight(chuck, bruce)) 40print(fight(dave, carl)) 41print(chuck.is_alive) 42print(bruce.is_alive) 43print(carl.is_alive) 44print(dave.is_alive) 45print(fight(carl, mark)) 46print(carl.is_alive) 47

試したこと

じつは最初、is_alive変数ではなくis_alive()メソッドだと勘違いして以下のコードを書いていました。このコードはちゃんと作動し正しい結果を与えたのですが、仕様と異なるせいか正解とは判定されませんでした。そこでメソッドの部分だけ変更したところ、上記のような事態になりました。

Python

1class Warrior: 2 def __init__(self): 3 self.health = 50 4 self.attack = 5 5 6 def is_alive(self): 7 if self.health > 0: 8 return True 9 else: 10 return False 11 12 13class Knight(Warrior): 14 def __init__(self): 15 super().__init__() 16 self.attack = 7 17 18 19def fight(unit_1, unit_2): 20 while unit_1.is_alive() and unit_2.is_alive(): 21 unit_2.health -= unit_1.attack 22 if unit_2.is_alive(): 23 unit_1.health -= unit_2.attack 24 25 if unit_1.is_alive(): 26 return True 27 else: 28 return False 29 30 31chuck = Warrior() 32bruce = Warrior() 33carl = Knight() 34dave = Warrior() 35mark = Warrior() 36 37 38print(fight(chuck, bruce)) 39print(fight(dave, carl)) 40print(chuck.is_alive()) 41print(bruce.is_alive()) 42print(carl.is_alive()) 43print(dave.is_alive()) 44print(fight(carl, mark)) 45print(carl.is_alive()) 46

なぜis_aliveがメソッドではないと思ったかというと、課題の中に示されていた例ではis_aliveのあとに()が付いていなかったからです(この判断は少し自信がありません。本当にメソッドではなく変数なのでしょうか?)。
課題中にあった例。is_aliveの後ろに()がなかったので、メソッドではないのかなと思いました(自信がありません)
###教えていただきたいこと
0. 「is_aliveは()が付いていないのでメソッドではなく変数」というのは正しいのか?
0. is_alive変数をどのように記述すればちゃんと動作するのか?

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

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

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

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

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

hayataka2049

2019/02/21 16:37

問題の出典はどこでしょうか
guest

回答2

0

「is_aliveは()が付いていないのでメソッドではなく変数」というのは正しいのか?

一般論としてはおおむねその通りです。ただし、propertyというものがあるので、「メソッドではなく属性」とは言えても「インスタンス変数である」とは言いづらいです。

また、文法上メソッドには()をつけなければ駄目なんてことはなく、つけなければそれはそれでメソッドオブジェクトが得られます(けど、呼び出していないので普通はあまり意味はない)。

is_alive変数をどのように記述すればちゃんと動作するのか?

まず知っておかないといけないことは、__init__はコンストラクタというもので、オブジェクトを作るとき(chuck = Warrior()など)に1回だけ呼ばれるということです。なのでその後更新されることはない訳です。

メソッドにしちゃうと駄目という仕様上の制約があるのであれば、やはりpropertyを使うことになるでしょう。以下の定義で、とりあえず正常終了はします(正しい結果かどうかは未チェック)。

python

1class Warrior: 2 def __init__(self): 3 self.health = 50 4 self.attack = 5 5 6 @property 7 def is_alive(self): 8 if self.health > 0: 9 return True 10 else: 11 return False

参考:
python property - Qiita
propertyについて - podhmoの日記

投稿2019/02/21 16:41

編集2019/02/21 16:44
hayataka2049

総合スコア30933

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

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

pupperccino

2019/02/22 07:39

ありがとうございました。 問題文中にpropertyという単語はあったのですが、まさか専門用語だとは思いませんでした。 propertyについて勉強してみようと思います。
hayataka2049

2019/02/22 07:47

1 property - is_alive, which can be True (if warrior's health is > 0) or False (in the other case) って書いてありましたね。
guest

0

ベストアンサー

Python

class Warrior:
def init(self):
...
# ここが怪しい
if self.health > 0:
self.is_alive = True
else:
self.is_alive = False

当該if文はインスタンスが生成したとき、一回だけ実行されます。
その後にhealthの値が変化したところで何ら動作には影響しません。

どうすれば解決できるか?

簡単な方法は主に二つ。
0. fight関数内でis_aliveの値もいじる
0. Warriorクラスに、healthを減算するためのメソッドを用意する

後者の方がお勧めです。
どちらにせよ、必要なタイミングで判定が走るようにしてやらないといけません。

一問一答

「is_aliveは()が付いていないのでメソッドではなく変数」というのは正しいのか?

はい。
修正: 今回は変数ではなくプロパティでしたね。変数と断定するのは早計でした。

TrueかFalseのどちらかの値を取り得るのであれば、おそらくbool型の変数です。

is_alive変数をどのように記述すればちゃんと動作するのか?

上述のとおり。
ダメージ判定をする際に生存を判定し、必要に応じて書き換えてやらねばなりません。

プログラムをコマンドプロンプトから実行したところ、終了しませんでした。

is_aliveの値が最初に設定されたまま一切更新されないので、常に両者生存の判定になります。

投稿2019/02/21 16:34

編集2019/02/22 08:05
LouiS0616

総合スコア35660

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

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

pupperccino

2019/02/22 07:36

ありがとうございました。__init__の挙動について理解が深まりました。 最終的にはhealth>0を判定するメソッドを定義し、while文の直後にis_alive変数に代入することで正解判定となりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問