[解決済み] eval、exec、compileの違いは何ですか?
質問
Pythonのコードの動的評価について調べていて、以下のものに出会いました。
eval()
と
compile()
関数、および
exec
ステートメントを使用します。
の違いについて、どなたか教えてください。
eval
と
exec
のモードがどのように異なるのか、また
compile()
が合うのでしょうか?
解決方法は?
短い答え、またはTL;DR
基本的には
eval
は、以下のように使用されます。
評価
動的に生成された1つのPython式を生成し
exec
は
エグゼクティブ
動的に生成された Python コードを、その副作用のためにのみ使用します。
eval
と
exec
は、この2つの違いがあります。
-
eval
のみを受け付けます。 単一表現 ,exec
は、Pythonのステートメント:ループを持つコードブロックを取ることができます。try: except:
,class
と関数/メソッドdef
といった具合になります。Pythonの式とは、変数に代入する値として持つことができるものなら何でもです。
a_variable = (anything you can put within these parentheses is an expression)
-
eval
は値を返します。 は与えられた式のexec
はそのコードからの戻り値を無視し、常にNone
(Python 2ではステートメントであり、式として使うことはできないので、実際には何も返しません)。
バージョン1.0~2.7では。
exec
を使用する関数に対して、CPython は異なる種類のコードオブジェクトを生成する必要があるため、ステートメントでした。
exec
を関数内の副作用のために使用します。
Python3では
exec
は関数です。その使用は、それが使用される関数のコンパイルされたバイトコードに何の影響も与えません。
このように基本的には
>>> a = 5
>>> eval('37 + a') # it is an expression
42
>>> exec('37 + a') # it is an expression statement; value is ignored (None is returned)
>>> exec('a = 47') # modify a global variable as a side effect
>>> a
47
>>> eval('a = 47') # you cannot evaluate a statement
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
a = 47
^
SyntaxError: invalid syntax
は
compile
で
'exec'
モードは、任意の数のステートメントを、暗黙のうちに常に
None
であるのに対し
'eval'
モードでは
シングル
をバイトコードに変換します。
を返します。
その式の値。
>>> eval(compile('42', '<string>', 'exec')) # code returns None
>>> eval(compile('42', '<string>', 'eval')) # code returns 42
42
>>> exec(compile('42', '<string>', 'eval')) # code returns 42,
>>> # but ignored by exec
で
'eval'
モード(したがって
eval
関数に文字列が渡された場合)、その文字列は
compile
は、ソースコードにステートメントや単一の式を超える何かが含まれている場合、例外を発生させます。
>>> compile('for i in range(3): print(i)', '<string>', 'eval')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
実はこの文は
"evalは単一の式しか受け付けません"
が適用されるのは、文字列(Pythonの
ソースコード
に渡されます。
eval
. その後,内部でバイトコードにコンパイルされます。
compile(source, '<string>', 'eval')
ここが本当に違うところです。
もし
code
オブジェクト(Python
バイトコード
に渡されます。
exec
または
eval
,
同じように動作する
を除いては
exec
は戻り値を無視し、依然として
None
は常に ですから
eval
を実行すると、ステートメントを持つ何かを実行するために、単に
compile
を文字列として渡すのではなく、バイトコードに変換してから渡してください。
>>> eval(compile('if 1: print("Hello")', '<string>', 'exec'))
Hello
>>>
は、コンパイルされたコードにステートメントが含まれていても、問題なく動作します。それでも
None
から返されるコードオブジェクトの戻り値であるためです。
compile
.
で
'eval'
モード(したがって
eval
関数に文字列が渡された場合)、その文字列は
compile
は、ソースコードにステートメントや単一の式を超える何かが含まれている場合、例外を発生させます。
>>> compile('for i in range(3): print(i)', '<string>'. 'eval')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
より長い答え、つまり血なまぐさい詳細です。
exec
と
eval
は
exec
関数(これは
Python 2 ではステートメント
) は、動的に作成された文やプログラムを実行するために使用されます。
>>> program = '''
for i in range(3):
print("Python is cool")
'''
>>> exec(program)
Python is cool
Python is cool
Python is cool
>>>
は
eval
関数は、同じように
単一表現
,
と
は式の値を返します。
>>> a = 2
>>> my_calculation = '42 * a'
>>> result = eval(my_calculation)
>>> result
84
exec
と
eval
は、実行されるプログラム/式を
str
,
unicode
または
bytes
ソースコードを含むオブジェクトとして、または
code
オブジェクト
で、Pythonのバイトコードを含んでいます。
もし
str
/
unicode
/
bytes
にソースコードが渡されました。
exec
と等価に動作する。
exec(compile(source, '<string>', 'exec'))
と
eval
と同等の振る舞いをする。
eval(compile(source, '<string>', 'eval'))
Pythonではすべての式が文として使えるので(これらは
Expr
ノードは、Pythonの
抽象文法
を使用することができます(逆は真ではありません)。
exec
のように、戻り値が不要な場合は つまり
eval('my_func(42)')
または
exec('my_func(42)')
という違いがあります。
eval
が返す値を返します。
my_func
であり、かつ
exec
はそれを破棄する。
>>> def my_func(arg):
... print("Called with %d" % arg)
... return arg * 2
...
>>> exec('my_func(42)')
Called with 42
>>> eval('my_func(42)')
Called with 42
84
>>>
2つのうち、唯一
exec
のようなステートメントを含むソースコードも受け付けます。
def
,
for
,
while
,
import
または
class
という代入文(別名
a = 42
)、あるいはプログラム全体が対象となります。
>>> exec('for i in range(3): print(i)')
0
1
2
>>> eval('for i in range(3): print(i)')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
両方
exec
と
eval
は、さらに2つの位置引数を受け付けます。
globals
と
locals
- は、コードが見ることのできるグローバル変数とローカル変数のスコープです。これらのデフォルトは
globals()
と
locals()
を呼び出したスコープ内で
exec
または
eval
には、どのような辞書でも使用することができます。
globals
と、任意の
mapping
に対して
locals
(を含む
dict
もちろんです)。これらはコードが見る変数を制限/変更するために使われるだけでなく、しばしば
exec
のコードで作成されます。
>>> g = dict()
>>> l = dict()
>>> exec('global a; a, b = 123, 42', g, l)
>>> g['a']
123
>>> l
{'b': 42}
(の値を表示する場合)。
g
のため、もっと長くなります。
exec
と
eval
として組み込みモジュールを追加します。
__builtins__
がない場合は自動的にグローバルに追加されます)。
Python 2 では、正式な構文として
exec
文は、実際には
exec code in globals, locals
というように
>>> exec 'global a; a, b = 123, 42' in g, l
しかし、代替構文
exec(code, globals, locals)
も常に受け入れられてきました(下記参照)。
compile
は
compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
ビルトインは、同じコードの繰り返し実行を高速化するために
exec
または
eval
ソースをコンパイルして
code
オブジェクトをあらかじめ作成しておきます。その
mode
パラメータは
compile
関数が受け入れ、生成するバイトコードの種類を指定します。選択肢は
'eval'
,
'exec'
と
'single'
:
-
'eval'
モードは単一の式を想定しており、実行されたときに その式 :>>> dis.dis(compile('a + b', '<string>', 'eval')) 1 0 LOAD_NAME 0 (a) 3 LOAD_NAME 1 (b) 6 BINARY_ADD 7 RETURN_VALUE
-
'exec'
は、単一の式からモジュール全体のコードまで、あらゆる種類の Python コンストラクトを受け入れ、それらがあたかもモジュールのトップレベル文であるかのように実行されます。コードオブジェクトはNone
:>>> dis.dis(compile('a + b', '<string>', 'exec')) 1 0 LOAD_NAME 0 (a) 3 LOAD_NAME 1 (b) 6 BINARY_ADD 7 POP_TOP <- discard result 8 LOAD_CONST 0 (None) <- load None on stack 11 RETURN_VALUE <- return top of stack
-
'single'
の限定形式です。'exec'
を含むソースコードを受け付けます。 シングル ステートメント(または、複数のステートメントを;
) 最後のステートメントが式ステートメントである場合、結果のバイトコードも が表示されます。repr
その式の値を標準出力に出力する(!) .An
if
-elif
-else
を持つループ、チェーンelse
を、そしてtry
とそのexcept
,else
とfinally
ブロックは1つの文とみなされます。トップレベルのステートメントを2つ含むソースフラグメントは
'single'
ただし、Python 2 では バグ で、コード内に複数のトップレベルステートメントが存在する場合がありますが、最初の1つだけがコンパイルされ、残りは無視されます。Python 2.7.8では。
>>> exec(compile('a = 5\na = 6', '<string>', 'single')) >>> a 5
そして、Python 3.4.2では。
>>> exec(compile('a = 5\na = 6', '<string>', 'single')) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1 a = 5 ^ SyntaxError: multiple statements found while compiling a single statement
これは対話的なPythonシェルを作るのに非常に便利です。しかし、式の値は 返されない を実行しても
eval
を実行すると、結果のコードが表示されます。
このように
exec
と
eval
は、実際には
compile
関数とそのモードです。
ソースコードをバイトコードにコンパイルするだけでなく。
compile
はコンパイルに対応しています。
抽象構文木
(Pythonコードのパースツリー)を
code
オブジェクトに、ソースコードは抽象的なシンタックスツリー (
ast.parse
はPythonで書かれており、単に
compile(source, filename, mode, PyCF_ONLY_AST)
複雑なケースでは、コードをテキストの行ではなく、ノードのツリーとして扱う方が簡単なことが多いからです。
一方
eval
は単一の式を含む文字列を評価することしかできませんが
eval
文全体、あるいはモジュール全体が
compile
バイトコードに変換されます。
print
はステートメントであり
eval
を直接導きます。
>>> eval('for i in range(3): print("Python is cool")')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print("Python is cool")
^
SyntaxError: invalid syntax
compile
とともに
'exec'
モードを
code
オブジェクトを作成すると
eval
それ
は
eval
関数が返す
None
.
>>> code = compile('for i in range(3): print("Python is cool")',
'foo.py', 'exec')
>>> eval(code)
Python is cool
Python is cool
Python is cool
を調べると
eval
と
exec
のソースコードをCPython 3で見ると、これは非常に明白で、両者とも
PyEval_EvalCode
は同じ引数で、唯一の違いは
exec
を明示的に返します。
None
.
の構文の違い
exec
Python 2 と Python 3 の間
Pythonの大きな違いの1つ
2
というのは
exec
は文であり
eval
は組み込み関数です(Python 3ではどちらも組み込み関数です)。
よく知られた事実ですが、公式の構文では
exec
は、Python 2 では
exec code [in globals[, locals]]
.
Python 2-to-3の大部分とは異なり
ポーティング
ガイド
見える
を提案する
は、その
exec
という構文で使用することもできます。
見た目
まさに
のように
exec
関数の呼び出しは、Python 3では 理由は、Python 0.9.9では
exec(code, globals, locals)
組み込み関数! そして、そのビルトイン関数は
exec
ステートメント
Python 1.0 リリース以前のどこかで
.
Python 0.9.9との後方互換性を壊さないことが望ましかったため。
Guido van Rossum は 1993 年に互換性ハックを追加しました。
: もし
code
が長さ2または3のタプルであり、かつ
globals
と
locals
に渡されることはありませんでした。
exec
ステートメントを使用する場合、そうでなければ
code
は、タプルの 2 番目と 3 番目の要素が
globals
と
locals
をそれぞれ作成しました。にも互換性ハックは記載されていませんでした。
Python 1.4 ドキュメント (オンラインで入手可能な最も古いバージョン)
そのため、移植ガイドやツールの作者の多くには、このことが知られることはありませんでした。
文書化
また
2012年11月
:
最初の式は、長さ2または3のタプルであってもよい。この場合、オプションの部分は省略しなければならない。形式は
exec(expr, globals)
は次のように等価です。exec expr in globals
という形式であるのに対しexec(expr, globals, locals)
と同等です。exec expr in globals, locals
. のタプル形式はexec
は、Python 3との互換性を確保するため、Python 3ではexec
は文ではなく、関数です。
そう、CPython 2.7では、前方互換性オプションであることが手際よく言及されています(なぜ後方互換性オプションがあることで人々を混乱させるのでしょうか)。 というのは、以前からあったのですが 20年来の後方互換性 .
このように、一方
exec
は、Python 1とPython 2では文、Python 3とPython 0.9.9では組み込み関数です。
>>> exec("print(a)", globals(), {'a': 42})
42
Jython 2.5.2, PyPy 2.3.1 (Python 2.7.6), IronPython 2.6.1 でも動きます (CPythonの文書化されていない挙動に忠実に従ったことに感謝します)。
Python 1.0 - 2.7 の互換性ハックではできないこと、それは
exec
を変数に格納します。
Python 2.7.11+ (default, Apr 17 2016, 14:00:29)
[GCC 5.3.1 20160413] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = exec('print(42)')
File "<stdin>", line 1
a = exec('print(42)')
^
SyntaxError: invalid syntax
(これは Python 3 でも有用ではないでしょう、なぜなら
exec
は常に
None
への参照を渡すか、あるいは
exec
:
>>> call_later(exec, 'print(42)', delay=1000)
File "<stdin>", line 1
call_later(exec, 'print(42)', delay=1000)
^
SyntaxError: invalid syntax
誰かが実際に使ったかもしれないパターン、ありえないけど。
リスト内包で使ったり。
>>> [exec(i) for i in ['print(42)', 'print(foo)']
File "<stdin>", line 1
[exec(i) for i in ['print(42)', 'print(foo)']
^
SyntaxError: invalid syntax
これはリスト内包の悪用である(
for
ループの代わりに!)。
関連
-
[解決済み】 AttributeError("'str' object has no attribute 'read'")
-
[解決済み] staticmethodとclassmethodの違いについて
-
[解決済み] callとapplyの違いは何ですか?
-
[解決済み] Pythonのリストメソッドであるappendとextendの違いは何ですか?
-
[解決済み] オブジェクト名の前のシングルアンダーコアとダブルアンダーコアの意味は何ですか?
-
[解決済み] 誰かPythonで__all__を説明してくれませんか?
-
[解決済み] リストとタプルの違いは何ですか?
-
[解決済み] re.searchとre.matchの違いは何ですか?
-
[解決済み】__str__と__repr__の違いは何ですか?
-
[解決済み】ilocとlocはどう違うのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Pythonによるjieba分割ライブラリ
-
Pythonの学習とデータマイニングのために知っておくべきターミナルコマンドのトップ10
-
任意波形を生成してtxtで保存するためのPython実装
-
Pythonの@decoratorsについてまとめてみました。
-
FacebookオープンソースワンストップサービスpythonのタイミングツールKats詳細
-
[解決済み】numpyの配列連結。"ValueError:すべての入力配列は同じ次元数でなければならない"
-
[解決済み】Pythonでgoogle APIのJSONコードを読み込むとエラーになる件
-
[解決済み】LogisticRegression: Pythonでsklearnを使用して、未知のラベルタイプ: '連続'を使用しています。
-
[解決済み】 TypeError: += でサポートされていないオペランド型: 'int' および 'list' です。
-
[解決済み】django インポートエラー - core.managementという名前のモジュールがない