Python
の exec()
関数は、動的にPython
コードを実行するための強力なツールです。文字列として渡されたコードや、動的に生成されたコードを実行する際に使用します。特に、複数行にわたるコードや、変数・関数定義などを含むスクリプトの実行に便利です。ただし、その強力さゆえに、セキュリティリスクも伴います。この記事では、 exec()
の使い方や応用例、セキュリティ上の注意点について解説します。
exec()関数とは?
exec()
関数は、渡された文字列やコードオブジェクトをPython
コードとして実行する組み込み関数です。通常、Python
コードはファイルに書かれて順次実行されますが、 exec()
を使うことでプログラム中に動的に生成されたコードや文字列を実行することができます。
基本的な構文
exec(object[, globals[, locals]])
- object:実行する
Python
コード。文字列またはコンパイル済みのコードオブジェクトを指定します。 - globals(オプション):グローバル名前空間を指定します。
- locals(オプション):ローカル名前空間を指定します。
exec()
は、与えられたコードを実行しますが、 値を返しません(関数の戻り値がない)。そのため、評価結果を取得する場合はeval()
を使用する必要があります。
exec()の使用例
基本的な使用例
まず、シンプルな例として、exec()
で1行のコードを実行してみます。
code = "print('Hello, World!')"
exec(code)
出力:
Hello, World!
この例では、exec()
に渡された文字列がPython
コードとして評価され、print()
文が実行されています。
複数行のコードを実行する
exec()
は複数行にわたるPython
コードも実行できます。例えば、変数の定義やループなどの複雑な処理を実行する場合にも使えます。
code = """
x = 10
y = 20
for i in range(3):
print(f'Iteration {i}: x + y = {x + y}')
"""
exec(code)
出力:
Iteration 0: x + y = 30
Iteration 1: x + y = 30
Iteration 2: x + y = 30
この例では、複数行のコードが1つの文字列として渡され、exec()
によって実行されています。
関数の定義を実行する
exec()
を使って関数を動的に定義し、実行することも可能です。
code = """
def greet(name):
return f'Hello, {name}!'
"""
# execで関数を定義
exec(code)
# 動的に定義された関数を呼び出す
result = greet('Alice')
print(result) # 出力: Hello, Alice!
このように、exec()
を使うことで、プログラムの実行時に関数を動的に定義し、その後に呼び出すことができます。
exec()の応用例
ユーザー入力によるコード実行
exec()
は、ユーザーの入力に基づいて動的にコードを実行することも可能です。例えば、簡易的なスクリプト言語のようなものを作成する場合、ユーザーが入力したコードを実行できます。
user_code = input("`Python`コードを入力してください: ")
exec(user_code)
例えば、user_code
に print("こんにちは")
と入力すると、exec()
がそのコードを実行して次のように出力します。
こんにちは
グローバルおよびローカル変数の操作
exec()
に渡すコードは、グローバルやローカルの名前空間を制御できます。これにより、外部から制限された環境でコードを実行することが可能です。
code = "x = 5"
# グローバル名前空間を制限
global_vars = {}
exec(code, global_vars)
print(global_vars) # 出力: {'__builtins__': {...}, 'x': 5}
print(global_vars['x']) # 出力: 5
この例では、exec()
に渡したコードが制限されたグローバル名前空間で実行され、x
の値が保存されます。
exec()の利点
動的なコード実行
exec()
の最大の利点は、 動的に生成されたコードを実行 できる点です。たとえば、プログラムが実行中に作られたコードを評価・実行したり、ユーザーの入力や外部データに基づいて動的に処理を変更したい場合に役立ちます。
複数行のコード実行
eval()
は1行の式しか評価できませんが、 exec()
は複数行のコードや複雑なスクリプトを実行できるため、柔軟性が高く、複雑な操作にも対応可能です。
exec()のセキュリティリスク
exec()
の柔軟性は非常に便利ですが、 セキュリティリスク も伴います。特に外部からの入力を exec()
に渡す場合、不正なコードが実行される可能性があるため、注意が必要です。
悪意のあるコードの例
次の例では、exec()
を使って危険なシステムコマンドを実行するコードが含まれています。
code = "import os; os.system('rm -rf /')" # 危険なコマンド
exec(code)
このコードが実行されると、システムのファイルが削除される可能性があり、非常に危険です。
セキュリティ対策
exec()
を使用する際には、次のようなセキュリティ対策を行うことが推奨されます。
- 信頼できる入力のみ使用する
ユーザーや外部からの入力をそのままexec()
に渡さないようにしましょう。常に入力データが安全であるか確認する必要があります。 - グローバル・ローカル名前空間を制限する
globals
やlocals
引数を使って、実行環境を制限する ことで、危険な操作が行われないようにすることが重要です。
safe_globals = {"__builtins__": None}
safe_locals = {}
code = "x = 2 + 3"
exec(code, safe_globals, safe_locals)
print(safe_locals['x']) # 出力: 5
この例では、__builtins__
を None
に設定することで、Python
の標準関数を無効にし、危険な操作を防止しています。
eval()との違い
Python
には eval()
という似たような機能を持つ関数がありますが、exec()
とは用途が異なります。
-
eval()
:1つの 式 を評価し、その結果を返します。結果が返るため、数式の評価や変数の値を動的に処理するのに適しています。 -
exec()
:複数行のコードや文を実行しますが、結果は返しません。スクリプトや関数定義など、複雑なコードの動的実行に向いています。
eval()の例
expression = "2 + 3 * 5"
result = eval(expression)
print(result) # 出力: 17
このように、eval()
は評価結果を返す一方、exec()
は文を実行するため、用途に応じて使い分けが必要です。
まとめ
Python
の exec()
関数は、複数行にわたるコードや動的に生成されたスクリプトを実行する強力なツールです。関数定義や複雑なコードを実行する際に便利で、動的なコードの処理を柔軟に行えます。しかし、 セキュリティリスク も伴うため、特に外部からの入力に対しては慎重に扱う必要があります。信頼できる入力のみを使用する、グローバル・ローカル名前空間を制限するなどの対策を講じて、exec()
を安全に活用しましょう。