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

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

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

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

Q&A

解決済

1回答

1141閲覧

(python)一つのプログラムとしては動くものが、モジュール化してみると上手く動作しない

sk_zappa

総合スコア5

Python 3.x

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

0グッド

0クリップ

投稿2021/06/23 18:45

前提・実現したいこと

pythonを学習中の初学者です。
モジュール化について勉強しており、ある完成されたプログラムにおいてモジュール化の練習を行っていたところ、上手く動作しませんでした。
どうしてモジュール化して分割したら上手くいかないのか、その原因を知りたいです。
以下、少し長くなるのですが、作っているものがどのようなプログラムかの説明です。あるpythonの教材を参考にしており、その説明を記します。

部屋からの群衆の避難のシュミレーションを行う。
◯部屋(room)は縱4、横5の20マスの格子で表現されています。出口はroom[0][0]です。人がいるマスは1、いないマスは0で、同じマスに複数人は入れません。
◯部屋の中の人は、毎ステップ、以下のフェーズ1とフェーズ2を両方この順で行います。なお、それぞれのフェーズでは全員が同時に移動するものとします。
【フェーズ1】(横方向の移動)
room[0][0]の人は脱出。(つまり、room[0][0]=1の場合は、room[0][0]=0に)。それ以外の位置room[i][j]にいる人は、[j]が0でなく、room[i][j-1]に人がいなければroom[i][j-1]に移動する。(つまり、room[i][j]=1、room[i][j-1]=0の場合は、room[i][j]=0、room[i][j-1]=1となる。)
【フェーズ2】(縦方向の移動)
room[0][0]の人は脱出。それ以外の位置room[i][j]にいる人は、[i]が0でなく、room[i-1][j]に人がいなければroom[i-1][j]に移動する。(つまり、room[i][j]=1、room[i-1][j]=0の場合は、room[i][j]=0、room[i-1][j]=1となる。)

部屋の初期状態と経過ステップ数を入力し、そのステップ数後の部屋の状態を求める関数を作りたい。

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

以下のプログラムを組み、関数ex5_7では理想通りに作動した。(教材の模範回答の通りの結果が出ました)
これを分割して、関数testと関数moveを作って連動させてみたところ、上手く作動しない。

該当のソースコード

python

1 2room = [[0, 1, 0, 1, 0], 3 [1, 0, 0, 1, 1], 4 [1, 1, 0, 1, 0], 5 [0, 0, 1, 0, 0]] 6 7def ex5_7(room, steps): 8 import copy 9 for i in range(0, steps): 10 #フェーズ1 11 room_new = copy.deepcopy(room) #現在の部屋のコピーを作成 12 if room_new[0][0] == 1: 13 room_new[0][0] = 0 #(0,0)にいる人は避難 14 for i in range(0, len(room)): 15 for j in range(1, len(room[0])): 16 if room[i][j] == 1 and room[i][j-1] == 0: #移動先に人がいないことを確認 17 room_new[i][j] = 0 18 room_new[i][j-1] = 1 #横に移動 19 #フェーズ2 20 room_new_2 = copy.deepcopy(room_new) #現在の部屋のコピーを作成 21 if room_new_2[0][0] == 1: 22 room_new_2[0][0] = 0 #(0,0)にいる人は避難 23 for k in range(1, len(room)): 24 for l in range(0, len(room[0])): 25 if room_new[k][l] == 1 and room_new[k-1][l] == 0: #移動先に人がいないことを確認 26 room_new_2[k][l] = 0 27 room_new_2[k-1][l] = 1 #縱に移動 28 room = copy.deepcopy(room_new_2) #最終的な部屋の状態を保存 29 return room 30 31def test(room, steps): 32 import copy 33 for i in (0, steps): 34 room = move(room) 35 return room 36 37def move(room): 38 import copy 39#フェーズ1 40 room_new = copy.deepcopy(room) #現在の部屋のコピーを作成 41 if room_new[0][0] == 1: 42 room_new[0][0] = 0 #(0,0)にいる人は避難 43 for i in range(0, len(room)): 44 for j in range(1, len(room[0])): 45 if room[i][j] == 1 and room[i][j-1] == 0: #移動先に人がいないことを確認 46 room_new[i][j] = 0 47 room_new[i][j-1] = 1 #横に移動 48#フェーズ2 49 room_new_2 = copy.deepcopy(room_new) #現在の部屋のコピーを作成 50 if room_new_2[0][0] == 1: 51 room_new_2[0][0] = 0 #(0,0)にいる人は避難 52 for k in range(1, len(room)): 53 for l in range(0, len(room[0])): 54 if room_new[k][l] == 1 and room_new[k-1][l] == 0: #移動先に人がいないことを確認 55 room_new_2[k][l] = 0 56 room_new_2[k-1][l] = 1 #縱に移動 57 room = copy.deepcopy(room_new_2) #最終的な部屋の状態を保存 58 return room 59

試したこと

過去に配列の参照点の問題でつまずいたので、配列を=で結ぶときはなるべくcopy.deepcopyでコピーを作るようにしている。
関数testのsteps部分の数値を色々変更させてみたのだが、出てくる結果はどれも同じものであった。

補足情報(FW/ツールのバージョンなど)

anaconda3のidleというものを使っています。
勉強のため、なぜ関数testと関数moveでは上手く動かないのか理由を知りたいです。
どうぞよろしくおねがいします。

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

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

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

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

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

takasima20

2021/06/23 20:59

とりあえず、グローバル変数名と関数の引数名とローカル変数名はかぶらないようにする方がいいと思います。
sk_zappa

2021/06/24 02:58

ご助言をありがとうございます。 そうだったのですね。考えてみれば、確かに同じものとして動作するわけではないので混乱してしまうかもしれません。 今後は被らないように記述するよう留意致します。
guest

回答1

0

ベストアンサー

実行結果は精査してませんが、
分割の際に一部コードが変わってしまった為ではないかな。

diff

1- for i in (0, steps): 2+ for i in range(0, steps):

投稿2021/06/23 21:46

teamikl

総合スコア8760

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

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

sk_zappa

2021/06/24 02:59

ありがとうございます。 ケアレスミスでした、ご指摘のとおりに直したところ、無事に作動しました…(すみません)。 寝ずに頭を抱えて悩んでいたのですが、脳が上手く動いてなかったようです。 こういうところにすぐ気付けるような実力を身に着けて行きたいと思います。 ありがとうございました。
teamikl

2021/06/24 05:16

答えそのものよりも、どのように問題を見つけるかを焦点にした方が良かったですね。>検索のヒント「デバッグ方法」 私が取った方法は、 双方のコードの一番上のfor 文の内側で print(i) を追記して steps=4 (適当に決めた小さな値)で実行です。 分割前のコード: 0, 1, 2, 3 分割後のコード: 0, 4 - 事前知識として、「range() は終端の値を含まない」という事を知っていて - ループ自体の回数も異なる事から ループ内のコードの問題ではなく、ループ自体が問題、と辺りを付けます。 ==== ## 2つのファイルを用意して、diff で比較。 簡易的には、ブラウザ内で試せるサービスもあります。 開発環境には大抵拡張機能で付いてます。残念ながらidleにはありません。 教材等、正常に動くコードがある場合に有効な方法です。 ## print() や logging でログを出力して結果を比較する。 一番外側のループから、ループ回数、ループ変数の遷移等を調べます。 場合によっては配列 room の変化も調べます。 ## デバッガを使い1行ずつステップ実行、変数の値の遷移を観察する。 これも、idle のデバッグ機能は、実行してる行をハイライトしてくれないと 他と比べて少し不親切なので、、、代案で モジュールを使わない簡単なコードなら、ブラウザで試せるものがあります http://pythontutor.com/ でステップ実行。 anaconda 環境があるなら、付属のIDE spyder の導入が候補。 ## 他にお勧めの方法としては、ユニットテスト(単体テスト) を 早期から導入すると良いかもしれません。 コードを編集 → 実行という手順でテスト行ってると思いますが、 環境を整備すると、関数単位でテストしたり、コード保存時に実行することもできます。 (これも idle では未対応)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問