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

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

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

Anacondaは、Python本体とPythonで利用されるライブラリを一括でインストールできるパッケージです。環境構築が容易になるため、Python開発者間ではよく利用されており、商用目的としても利用できます。

Python 3.x

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

Q&A

1回答

214閲覧

Pythonにて既存のコードをループ文にエラーがでないよう移行させたい

pythonwakaran

総合スコア1

Anaconda

Anacondaは、Python本体とPythonで利用されるライブラリを一括でインストールできるパッケージです。環境構築が容易になるため、Python開発者間ではよく利用されており、商用目的としても利用できます。

Python 3.x

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

0グッド

0クリップ

投稿2024/11/01 08:50

編集2024/11/01 08:52

実現したいこと

Python初心者です。
Pythonを使用してcsvデータを読み込み、それを分析するためのプログラムを作成中です。
実現したいことは作成したプログラムを条件によって続けるか分岐させるため、def main、while文にてループさせたいのですが、def main内でのインスタンス化等がうまくできません。

発生している問題・分からないこと

実際のコードはあまりにも長すぎるため、ここでは問題点を解決するための簡易にしたコードを貼らせていただきます。一番の問題はクラス「TestData2」内で実際のコードでは「df_test」にあたるデータフレームの変数が複数存在しており、def main内でインスタンス化や元々のコードの最後の部分をそのまま移行すると、「df_test」に当たる部分が定義されていませんとエラーになっています。しかし一部だけをdef main外(def mainの前で定義)すると文字変換エラー等がでてしまいます。(おそらくTestDeta1の変換がうまくいかなくなってしまっているため)。「df_test」を「self.df_test」にしてみたこともあるのですが、あまりにもエラーが多発したのと、できればグローバル変数にするのも避けたいです。

該当のソースコード

import chardet import pandas as pd import numpy as np import datetime from datetime import datetime, timedelta class TestData1: def __init__(self, file_path): self.state = 'initial' # 初期状態 self.file_path = file_path self.df_test = None # 初期化 def load_data(self): with open(self.file_path, 'rb') as f: binary = f.read() d = chardet.detect(binary) if d["encoding"] == "utf-8": enco = "utf-8" elif d["encoding"] == "UTF-8-SIG": enco = "utf_8_sig" else: enco = "SHIFT-JIS" self.df_test = pd.read_csv(self.file_path, encoding=enco, header=None, usecols=range(44), skiprows=[0], nrows=301) return self.df_test def convert_data_types(self): self.df_test.iloc[0:1, 0:44] = self.df_test.iloc[0:1, 0:44].astype(str) self.df_test.iloc[1:301, 0] = pd.to_datetime(self.df_test.iloc[1:301, 0], format='%H:%M:%S', errors='coerce').dt.time self.df_test.iloc[1:301, 41] = pd.to_datetime(self.df_test.iloc[1:301, 41], format='%H:%M:%S', errors='coerce').dt.time self.df_test.iloc[1:301, 1:41] = self.df_test.iloc[1:301, 1:41].astype(float) self.df_test.iloc[1:301, 42:44] = self.df_test.iloc[1:301, 42:44].astype(float) def print_data(self): print(self.df_test) print("Class1実行完了") self.state = 'updated' # インスタンス変数を更新 # クラスのインスタンスを作成 data_test1 = TestData1("C:\\Users\\PC_User\\Desktop\\test_csv\\Sheet1.csv") df_test = data_test1.load_data() data_test1.convert_data_types() data_test1.print_data() class TestData2: def __init__(self, df_test): self.state = 'initial' # 初期状態 self.df_test = df_test self.label_dict = {} self.test1 = None # 初期化 self.test2 = float('-inf') def process_label_test(self,label): if label in self.label_dict: top_row = self.label_dict[label][0] time = df_test.iloc[top_row-2, 41] time_plus_one_sec = (datetime.combine(datetime.date.today(), time) + timedelta(seconds=1)).time() closest_time_row = self.df_test.iloc[(self.df_test.iloc[1:301,0].apply(lambda x: x.hour*3600 + x.minute*60 + x.second) - (time_plus_one_sec.hour*3600 + time_plus_one_sec.minute*60 + time_plus_one_sec.second)).abs().argsort()[:1]] self.test1 = closest_time_row.iloc[0, 11] def label_answer_test(self): for label in ['A', 'B', 'C', 'D', 'E', 'F']: result = self.process_label_test(label) if result == self.test1: print("成功") print("Class2実行完了") self.state = 'updated' # インスタンス変数を更新 # クラスのインスタンスを作成 deta_test2 = TestData2(df_test) deta_test2.label_answer_test() class TestData3: def __init__(self): self.state = 'initial' # 初期状態 def test_3(self): print("test3実行") self.state = 'noneupdated' # インスタンス変数を更新 print("Class3実行完了") 以上の文をループさせるため、各コードの「#クラスのインスタンスを作成」の部分を下記のコードにうまく当てはめたいです。 # ループ文を作成 def main(): class1_instance = TestData1() class2_instance = TestData2() class3_instance = TestData3() while class3_instance.state != 'updated': class1_instance.load_data() class1_instance.convert_data_types() class1_instance.print_data() class2_instance.process_label_test() class2_instance.label_answer_test() class3_instance.test_3() break print("Done!") if __name__ == "__main__": main()

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

いくつか試しましたがエラーを解決することができませんでした。何卒宜しくお願い致します。

補足

特になし

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

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

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

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

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

meg_

2024/11/01 11:00

該当のソースコード を実行すると言われるようなエラーが発生するのでしょうか?そうでない場合「ここでは問題点を解決するための簡易にしたコード」では問題解決は難しいかもしれません。プログラムを小さく作って、エラーが出ない状態のプログラムを改良していってはどうでしょうか?
pythonwakaran

2024/11/01 11:36

ご回答ありがとうございます。一旦目先の課題解決がクラスTest1,Test2の # クラスのインスタンスを作成 data_test1 = TestData1("C:\\Users\\PC_User\\Desktop\\test_csv\\Sheet1.csv") df_test = data_test1.load_data() data_test1.convert_data_types() data_test1.print_data() deta_test2 = TestData2(df_test) deta_test2.label_answer_test() この部分を最後のループ文に当てはめた場合に「df_test」が定義されていません。と元のコードで多くエラーが出てしまうのをなんとかしたいと思い投稿した次第です。投稿のコードは実際コードで定義されていないと出るdf_testが含まれる最初の部分までで区切っています。def main内への移行の際に定義エラーがでなければそのまま移行できると思うのでできればそうしたいと思っています。
melian

2024/11/01 12:14

定義エラーが発生しているのは TestData2 クラスの process_label_test() メソッドではないでしょうか。 def process_label_test(self,label):  if label in self.label_dict:   top_row = self.label_dict[label][0]   # df_test.iloc[...] ではなく self.df_test.iloc[...]   #time = df_test.iloc[top_row-2, 41]   time = self.df_test.iloc[top_row-2, 41]
pythonwakaran

2024/11/01 12:43

ご回答ありがとうございます。エラーでているdf_testにすべてselfをつけるもしくはメソッドの引数にdf_testを指定すれば定義エラー自体はでないのですが、他の不具合が多発するのでさけたいと思っています。ループ文に入れなけらば定義エラーはでないことも考えると本文コード自体を触らずにインスタンス化周りの部分の定義でなんとかならないかと思っている次第です。
melian

2024/11/01 13:22

> 他の不具合が多発するので その不具合を根本的に解決するべきかとは思いますが。。。
TakaiY

2024/11/01 13:33

> ループ文に入れなけらば定義エラーはでないことも考えると本文コード自体を触らずにインスタンス化周りの部分の定義でなんとかならないかと思っている次第です。 すでにクラス定義にグローバルデータを誤って参照してしまっている場所があるなど、コード自体に問題があり、他にも問題がありそうなので、そこはちゃんと直すべきです。
pythonwakaran

2024/11/01 13:42

行き違いコメントになりましたが、本文コード自体を修正するしか方法はなさそうということなので、そちらの方向で見直してみます。どうもありがとうございました!
guest

回答1

0

クラスの中身は見てませんが、もとのトップレベルの処理だけ見てmainを書いてみると以下のような感じでしょう。

python

1def main(): 2 while True: 3 # クラスのインスタンスを作成 4 class1_instance = TestData1("C:\\Users\\PC_User\\Desktop\\test_csv\\Sheet1.csv") 5 class1_df = class1_instance.load_data() 6 class1_instance.convert_data_types() 7 class1_instance.print_data() 8 # クラスのインスタンスを作成 9 class2_instance = TestData2(class1_df) 10 class2_instance.label_answer_test() 11 # クラス3のインスタンスを作成 12 class3_instance = TestData3() 13 class3_instance.test_3() 14 15 if class3_instance.state != 'updated': 16 break 17 18 print("Done!")

で、これは動きそうにありません。動かすために必要な情報が欠けています

  • ループの度に何か更新されなければなりません。
    ループにするということは、条件を満たすまで何かを変更しないと無限ループになりますが、何を変更するのかが不明です。
    とりあえず、ループの度にすべてのインスタンスを生成するようにしてありますが、たとえば、最初のCSVを違うものにするなどでしょうか。
    または、いずれかのメソッドを呼ぶだけで更新されるのでしょうか。その場合、いくつかの初期化をループの外に出せるかもしれません。
  • 質問のコードのclass3は、他のインスタンスと関連が無いので、どのようにあつかったらいいかわからない。
    実際のコードそのものではないということなので、それが原因とは思いますが。

投稿2024/11/01 09:57

編集2024/11/01 12:35
TakaiY

総合スコア13687

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

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

pythonwakaran

2024/11/01 11:03

ご回答ありがとうございます。ややこしくてすみません。簡単に申し上げますとクラスTest1,Test2はもともとそれ単独のコードなのですがループさせるために # クラスのインスタンスを作成 data_test1 = TestData1("C:\\Users\\PC_User\\Desktop\\test_csv\\Sheet1.csv") df_test = data_test1.load_data() data_test1.convert_data_types() data_test1.print_data() deta_test2 = TestData2(df_test) deta_test2.label_answer_test() この部分を最後のループ文にうまくいれたいのです。テスト用なので実際の挙動については質問のコードでは気にしていません。クラスTestData2にて変数「df_test」が実際のコードでは多く扱われておりインスタンス化等の上記の部分のコードをそのままdef main内に持ち込むと「df_test」が定義されていません。となるのが主に困っている点となります。宜しくお願いします。
pythonwakaran

2024/11/01 11:51

なので先ほどのコードを当てはめさせていただいた場合、それぞれdf_test、df_test1、df_test2が定義されていませんとなってしまいます
pythonwakaran

2024/11/01 12:02

それぞれのメソッドの引数にdf_testをいれれば定義問題は解決できるのですが、それをするとそれ以外の部分でおおくの不具合がでていまうので、できれば本文メソッドのコードをあまり変更しない方法があればおねがいしたいです。宜しくお願いします。
TakaiY

2024/11/01 12:39

コードにミスがあったの>で修正しました。 > df_test、df_test1、df_test2が定義されていませんとなってしまいます コメントで指摘されていますが、これらのエラーは、コードのバグによるものの可能性が高いですね。 本来、コンストラクタ(__init__())で取り込み設定されているメンバ変数でなく、グローバル変数を参照するようになっているのが原因の可能性が高いです。 エラーメッセージをよく確認して、問題を修正する必要があります。 これまで顕在化しなかったのは、間違って参照されているグローバル変数がたまたま存在したからと思われます。
pythonwakaran

2024/11/01 13:38

つまりdef mainへの入れ方の問題ではなく定義できない不具合が出ること自体が問題であり、元のコードのバグを直すしかないということでしょうか?
TakaiY

2024/11/02 01:16

基本的にはそうです。 ループ前のコードがそれなりに動いていたということは、誤魔化しながら使い続けることはできるでしょうが、いずれ難しい問題に直面することになる可能性が高いです。 コメントで指摘されているとおり、TestData2クラスの中に現れる、selfの付いていない「df_test」という変数は、クラス定義の「外」にあるものを参照しようとしています。定義の外にあるものなので、今回の用意状況が変化するとすぐに影響を受けて使えなくなるし、場合によっては競合してニッチもサッチもいかなくなるかもしれません。 df_test1、df_test2についても同様です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問