Help us understand the problem. What is going on with this article?

Python の eval と exec

More than 3 years have passed since last update.

はじめに

これまで Python の evalexec についてよく分かっていなかったので調べてみました。もし誤りがあれば指摘いただけたらと思います。

特に断りがない限り、Python のバージョンは 3.6.1 の内容になります。

eval とは

eval は第1引数をとして評価します。次は簡単な例です。

>>> eval('1 + 2')
3

次は第1引数が式ではなく文(代入文)になるので、エラーになります。

>>> eval('a = 1 + 2')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    a = 1 + 2
      ^
SyntaxError: invalid syntax

Python の式と文について、詳しくは次のドキュメントを参考にしてください。

また、出力結果の通り、評価の結果が戻り値となります。

>>> a = eval('1 + 2')
>>> a
3

compile について

eval の第1引数には文字列以外を指定する事ができます。次は compile() で生成したバイトコードを指定した例です。

>>> eval(compile('1 + 2', '<string>', 'eval'))
3

eval の第2引数、第3引数

eval は第2引数としてグローバル、第3引数としてローカルな名前空間を指定できます。

次はローカル名前空間に変数 a を指定した例です。

>>> eval('a * 3', {}, {'a': 2})
6

次はグローバルとローカル名前空間に同じ名前の a を指定した例です。

>>> eval('a', {'a': 20}, {'a': 10})
10

ローカル名前空間が優先して参照されることが分かります。

exec とは

exec は第1引数をとして実行します。次は簡単な例です。

>>> exec('a = 1 + 2')

ここでは代入が実行されるだけで、評価した値は返らないため結果は出力されません。exec の戻り値は常に None になります。

>>> exec('a = 1 + 2') is None
True

ただし、変数 a に評価した値が代入されているため、例えば print によって内容を確認できます。

>>> exec('print(a)')
3

第1引数には eval 同様に文字列だけでなく、例えばバイトコードを指定することが出来ます。

exec の第2引数、第3引数

exec も第2引数、第3引数でそれぞれグローバル、ローカルな名前空間を指定することが可能です。

次はローカル名前空間として a10 を指定して実行した例です。

>>> exec('print(a)', {}, {'a': 10})
10

次はローカルな名前空間として空のディクショナリを渡した例です。

>>> a = {}
>>> exec('b = 3', {}, a)
>>> a
{'b': 3}

代入した値が参照できることが分かります。これに対して eval は式の評価なので、名前空間の値を変更する事ができません。

組み込み参照の制限

exec によってグローバル名前空間を変更または参照される事を制限したい事があります。例えば、ユーザから受け取った入力を実行する場合です。

この場合、第2引数に __builtins__ ディクショナリを指定する事で、実行時の組み込みを制限できます。

>>> exec('import os;os.system("echo danger!")', {}, {})
danger!
>>> exec('import os;os.system("echo danger!")', {'__builtins__':None}, {})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
ImportError: __import__ not found

この例では __builtins__ ディクショナリに None を指定しているので import os 実行時の呼び出しで __import__ が見つからずにエラーになっています。

eval と exec の違い

簡単にまとめると次のようになります。

eval exec
第1引数をどうするか 評価 実行
第1引数 式 
戻り値 評価の結果 None

参考

kyoshidajp
ねる、くう、はしる
https://kyoshida.jp
jmty
日本最大のクラシファイドサイト「ジモティー」を開発・運営するスタートアップ
http://jmty.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away