概要
文字列を式として認識してくれるeval
関数を使ってみたので紹介します。
サンプルコード
eval
関数は、文字列として渡されたPython式を評価し、その結果を返す関数。
以下公式ドキュメント。
以下、作成したサンプルコードです。
expression = "1 + 2 * 3"
eval_result = eval(expression)
print(f"Expression: {expression}, Eval_Result: {eval_result}")
# Expression: 1 + 2 * 3, Eval_Result: 7
上記の通り、Expression
の方では単なる文字列として出力されていますが、Eval_Result
では文字列が式として評価されています。
ただし、こちら検索するとすぐに「脆弱性」「リスク」と言うワードが目に入ります。
と言うのも、計算式だけではなく、コマンドも実行できてしまうからです。
実際、悪意のあるコードが実行される可能性もあるため、使用する際は注意が必要です。
グローバル変数とローカル変数
上記のリスク回避のために、グローバル変数とローカル変数を指定することができます。
それぞれ、eval
関数の第二、第三引数です。
以下、それらを追加したサンプルコード。
allowed_globals = {"__builtins__": None}
allowed_locals = {"x": 1, "y": 2, "z": 3}
expression = "x + y * z"
result = eval(expression, allowed_globals, allowed_locals)
print(f"Expression: {expression}, Result: {result}")
__builtins__
をNone
に設定することで、eval
関数がデフォルトの組み込み関数にアクセスできないようになります。例えばos.remove
などでファイル削除するようなコマンドが実行できなくなります。
__builtins__
とは...
builtins
モジュールを使えるグローバル変数です。
builtins
モジュールとは以下の通りで、組み込み関数へアクセスできます。
Python の全ての「組み込み」識別子に直接アクセスするためのもの
https://docs.python.org/ja/3/library/builtins.html
また、allowed_locals
に「名前空間」を指定しそこで変数を設定したことで、特定のローカル変数のみの使用制限が実現できています。これで予期しない変数や関数へアクセスされることがなくなります。
上記で実行すると出力結果は以下のようになります。
Expression: x + y * z, Result: 7
ただし、上記Qiita記事はじめ、実運用に使う場合はリスクを払拭し切れるわけではないようですので、利用の際は他の方法も検討することをお勧めします。