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

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

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

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

Q&A

解決済

3回答

282閲覧

1度のみeVal()を使う場合での処理高速化

infra_se_124

総合スコア3

Python

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

1グッド

1クリップ

投稿2024/11/13 08:12

実現したいこと

どうしても、ユーザーが入力したテキストファイルに記述してある式を実行する必要があります。
eVal()関数で実行はできたのですが、同じ式を10000回繰り返す必要があり
もともとのPythonプログラムに記述した場合と比べて、かなり遅い結果となることがわかりました。

プログラム実行中にテキストファイルに記述する式が変化するのであれば
eVal()で文字列を都度、式に評価する以上、遅くなるのは仕方ないと思いますが
プログラム起動時のみテキストファイルに記述している文字列を1度だけ読み込むので
高速化できるのであればしたいと考えています。

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

高速化する方法がわからない

該当のソースコード

Python

1import math 2import time 3 4 5def read_expressions(filename): 6 try: 7 with open(filename, 'r') as file: 8 return [line.strip() for line in file if line.strip()] 9 except FileNotFoundError: 10 print(f"ファイル '{filename}' が見つかりません。") 11 return [] 12 except Exception as e: 13 print(f"ファイル読み込み中にエラーが発生しました: {str(e)}") 14 return [] 15 16 17def evaluate_expression(expression, variables): 18 # 文字列をeVal関数で評価して実行する 19 # セキュリティのため四則演算と三角関数、ルート、pi、e、最大、最小、絶対値以外の関数は使わせない 20 # main関数で定義している変数は使用OK 21 safe_dict = { 22 'abs': abs, 'max': max, 'min': min, 23 'sin': math.sin, 'cos': math.cos, 'tan': math.tan, 24 'sqrt': math.sqrt, 25 'pi': math.pi, 'e': math.e 26 } 27 safe_dict.update(variables) 28 29 try: 30 result = eval(expression, {"__builtins__": None}, safe_dict) 31 return result 32 except Exception as e: 33 return f"エラー: {str(e)}" 34 35 36def main(): 37 38 # ユーザーがテキストファイルに書いた式(文字列)をロードする 39 filename = "expressions.txt" 40 expressions = read_expressions(filename) 41 42 kakudo_Value = 30 43 Force_Value = 10.55 44 45 variables = { 46 'kakudo_Value': kakudo_Value, 47 'Force_Value': Force_Value 48 } 49 50 for expression in expressions: 51 52 # ユーザーが設定したテキストファイルの式を10000回繰り返す 53 start_time = time.time() 54 for i in range(10000): 55 result = evaluate_expression(expression, variables) 56 print(time.time() - start_time) 57 print(f"式: {expression}") 58 print(f"結果: {result}") 59 60 # 【比較用】ユーザーが設定したテキストファイルの式と同じ式を10000回繰り返す 61 start_time = time.time() 62 for i in range(10000): 63 kekka = math.sin(kakudo_Value * math.pi / 180) * Force_Value 64 print(time.time() - start_time) 65 print(f"結果: {kekka}") 66 67 68if __name__ == "__main__": 69 main() 70
sin(kakudo_Value * pi / 180) * Force_Value
特になし

試したこと・調べたこと

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

functools.cacheを使えばいいかもと思いましたが、ソースコード上では定数として設定している変数のkakudo_ValueとForce_Valueは、実際には変化しますので、あまり高速化できないのでは無いかと考えました。

補足

特になし

melian👍を押しています

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

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

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

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

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

guest

回答3

0

ベストアンサー

文字列をコードオブジェクトにコンパイルしてやると少しは早くなると思います。
https://docs.python.org/ja/3/library/functions.html#compile

python

1for expression in expressions: 2 start_time = time.time() 3 compiled = compile(expression, '<string>', 'eval') 4 for i in range(10000): 5 result = evaluate_expression(compiled, variables) 6 print(time.time() - start_time) 7 print(f"結果: {result}")

機械語へのコンパイルではないので、そんなに高速化できないですが、毎回構文解析しなくてよくなる分、早くなると思います。

投稿2024/11/14 11:57

bsdfan

総合スコア4774

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

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

infra_se_124

2024/11/15 09:22

回答ありがとうございます。 コンパイルしないときに比べて10倍ほど速度改善致しました!
guest

0

式(文字列)から lambda 関数を作成して実行します。

python

1def main(): 2 # ユーザーがテキストファイルに書いた式(文字列)をロードする 3 filename = "expressions.txt" 4 expressions = read_expressions(filename) 5 6 kakudo_Value = 30 7 Force_Value = 10.55 8 9 variables = { 10 'kakudo_Value': kakudo_Value, 11 'Force_Value': Force_Value 12 } 13 14 safe_dict = { 15 'abs': abs, 'max': max, 'min': min, 16 'sin': math.sin, 'cos': math.cos, 'tan': math.tan, 17 'sqrt': math.sqrt, 18 'pi': math.pi, 'e': math.e 19 } 20 21 for expression in expressions: 22 # ユーザーが設定したテキストファイルの式を10000回繰り返す 23 start_time = time.time() 24 f = eval('lambda: ' + expression, safe_dict|variables) 25 for i in range(10000): 26 result = f() 27 print(time.time() - start_time) 28 print(f"式: {expression}") 29 print(f"結果: {result}") 30 31 # 【比較用】ユーザーが設定したテキストファイルの式と同じ式を10000回繰り返す 32 start_time = time.time() 33 for i in range(10000): 34 kekka = math.sin(kakudo_Value * math.pi / 180) * Force_Value 35 print(time.time() - start_time) 36 print(f"結果: {kekka}") 37 38# 0.0017275810241699219 39# 式: sin(kakudo_Value * pi / 180) * Force_Value 40# 結果: 5.2749999999999995 41# 0.0015337467193603516 42# 結果: 5.2749999999999995

ソースコード上では定数として設定している変数のkakudo_ValueとForce_Valueは、実際には変化しますので、あまり高速化できないのでは無いかと考えました。

kakudo_ValueForce_Valueが変化する場合は、variables(dict)の内容を変更して f = eval('lambda: ' + expression, safe_dict|variables) の実行を繰り返すことになりますので、言われる通りに高速化は見込めないかもしれません。

投稿2024/11/14 02:08

melian

総合スコア20574

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

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

infra_se_124

2024/11/15 08:53

回答ありがとうございます。 ベストアンサーは別の方を選ばせていただきましたが、こちらの回答も非常に参考になりました。
guest

0

exec(‘def f(kakudo_value,force_value): return ‘+expression)
とかを実行して、pythonの関数にしたfを呼べぶのはどうでしょう。
変数は全部引数として渡す必要はありますけど。

投稿2024/11/13 09:55

matukeso

総合スコア1677

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

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

infra_se_124

2024/11/15 09:21

回答ありがとうございます。 ただ、残念ながら返って処理は遅くなってしまいました。。 ですが、このような使い方は知らなかったので ご教示いただけたのは大変ありがたかったです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問