eval、exec、compileの違いは何ですか?


428

私はPythonコードの動的評価を検討しており、eval()およびcompile()関数とexecステートメントに出くわしました。

evalとの違い、およびexecさまざまなモードがどのようにcompile()適合するかを誰かが説明できますか?

回答:


517

短い答え、またはTL; DR

基本的evalに使用される評価 uate単一動的に生成されたPythonの式を、とexecするために使用されるEXECのみ、その副作用のUTE動的に生成されたPythonコード。

evalそしてexecこれら2つの違いがあります。

  1. evalのみ受け付ける単一の発現をexecループ、:Pythonの文有するコードブロック取ることができtry: except:class及び関数/メソッドのdefようにinitionsとします。

    Pythonの式は、変数割り当ての値として使用できるものです。

    a_variable = (anything you can put within these parentheses is an expression)
  2. eval 与えられた式のexec返しますが、コードからの戻り値は無視し、常に戻りますNone(Python 2ではステートメントであり、式として使用できないため、実際には何も返しません)。

バージョン1.0から2.7では、execCPython execは関数内の副作用に使用される関数に対して異なる種類のコードオブジェクトを生成する必要があったため、ステートメントでした。

Python 3では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としてのいずれかで実行されるプログラム/発現受け入れる両方strunicodeまたはbytesソースコードを含むオブジェクト、又はcodeオブジェクトのPythonバイトコードを含んでいます。

場合str/ unicode/ bytes含むソースコードはに渡されたexec、それはに同等に動作します。

exec(compile(source, '<string>', 'exec'))

eval同様に、次と同等に動作します。

eval(compile(source, '<string>', 'eval'))

すべての式はPythonでステートメントとして使用できるため(これらはExprPython 抽象文法ではノードと呼ばれ、その逆は当てはまりません)、exec戻り値が必要ない場合はいつでも使用できます。つまり、eval('my_func(42)')またはのいずれかを使用できます。exec('my_func(42)')違いevalは、によって返された値を返し、それmy_funcexec破棄することです。

>>> 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ステートメントが含まれてソースコードを受け入れるようにdefforwhileimport、または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

両方ともexeceval2つの追加の位置引数- globalslocals-を受け入れます。これらは、コードが認識するグローバル変数スコープとローカル変数スコープです。これらのデフォルトglobals()locals()呼ばれることの範囲内execevalが、任意の辞書を使用することができためglobals、あらゆるmappingについてlocals(含むdict、もちろん)。これらは、コードに表示される変数を制限/変更するためだけでなく、executedコードが作成する変数をキャプチャするためにも使用できます。

>>> 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標準出力にその式の値を(!)

    if- elif- elseチェーン、とループelse、およびtryそのでexceptelseそしてfinallyブロックは、単一のステートメントとみなされます。

    2つのトップレベルステートメントを含むソースフラグメントは、のエラーです'single'。ただし、Python 2 では、コード内に複数のトップレベルステートメントを許可するバグがある場合があります。最初のものだけがコンパイルされます。残りは無視されます:

    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

したがって、機能とそのモードの最大の違いはexeceval実際にはcompileその機能とモードに由来します。


ソースコードをバイトコードにコンパイルすることに加えて、抽象構文ツリー(Pythonコードの解析ツリー)のオブジェクトへのコンパイルをcompileサポートします。そして、ソースコードを抽象構文ツリーに入れます(これはPythonで記述され、を呼び出すだけです)。これらは、複雑なケースではコードをテキスト行ではなくノードのツリーとして処理する方が簡単な場合が多いため、ソースコードをオンザフライで変更する場合や動的コード作成などに使用されます。codeast.parsecompile(source, filename, mode, PyCF_ONLY_AST)


一方でeval唯一あなたが単一の式を含む文字列を評価することを可能にする、あなたのことができeval文全体、あるいはされていても、モジュール全体compileバイトコードにdは、つまり、Python 2では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

CPython 3を調べてソースコードを調べるevalexec、これは非常に明白です。どちらもPyEval_EvalCode同じ引数で呼び出しますが、唯一の違いはexec明示的にを返すことNoneです。

execPython 2とPython 3の構文の違い

Python 2の主な違いの1つは、それexecがステートメントでevalあり、組み込み関数であることです(どちらもPython 3の組み込み関数です)。execPython 2の公式構文がであることはよく知られている事実ですexec code [in globals[, locals]]

2対3のPythonの大半とは異なりポーティング ガイドは 思え 示唆しexecCPythonの2の文では、という構文で使用することができルックス 正確のようなexecPythonの3の関数呼び出しの理由は、Python 0.9.9が持っていたということですexec(code, globals, locals)内蔵の機能中!そして、その組み込み関数は、Python 1.0がリリースされる前のどこかのexecステートメントで置き換えられました。

Python 0.9.9との後方互換性を壊さないことが望ましいため、Guido van Rossumは1993年に互換性ハックを追加しました。これcodeが長さ2または3のタプルでありglobals、それ以外localsexecステートメントに渡されなかった場合、はcode解釈されますタプルの2番目と3番目の要素がそれぞれglobalsandでlocalsあるかのように。互換性のハックは、Python 1.4のドキュメント(オンラインで最も古いバージョン)でも言及されていませんでした。そのため、2012年11月に再び文書化れるまで、移植ガイドとツールの多くの作成者には知られていませんでした。

最初の式は、長さ2または3のタプルにすることもできます。この場合、オプションの部分は省略する必要があります。フォームexec(expr, globals)はと同等ですがexec expr in globals、フォームexec(expr, globals, locals)はと同等exec expr in globals, localsです。のタプル形式は、ステートメントではなく関数であるexecPython 3との互換性を提供しますexec

はい。CPython2.7では、20年間実際に下位互換性のために存在していたのに、前方互換性オプションであると簡単に呼ばれています(後方互換性オプションがあることで人々を混乱させるのはなぜですか)。

したがってexec、Python 1とPython 2のステートメント、およびPython 3とPython 0.9.9の組み込み関数は、

>>> exec("print(a)", globals(), {'a': 42})
42

これまでに広くリリースされたすべてのPythonバージョンで同じ動作をした可能性があります。また、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

(これは、exec常にを返すため、Python 3では役に立ちません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代わりにループを使用してください)。


[i for i in globals().values() if hasattr(i, '__call__')][0]文または式は?式だったのに、なぜ@デコレータとして使えないのですか?
マリオ

それは表現です。42も式であり@、デコレータとしては使用できません。
Antti Haapala 2015年

デコレータ構文は次のとおりですdecorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE。つまり、任意の式をデコレータとして使用することはできません。(ドットで区切られた)識別子と、それに続くオプションの呼び出し引数のみを使用できます。
Antti Haapala 2015年

1
割り当ての右側に配置してコンパイルできるものはどれも式です。たとえば、a = b = cはその右辺と同様に完全に有効なステートメントですb = c-これは式ではありません。
トム

194
  1. execは式ではありません。Python2.xではステートメント、Python 3.xでは関数です。文字列に含まれるステートメントまたはステートメントのセットをコンパイルし、すぐに評価します。例:

    exec('print(5)')           # prints 5.
    # exec 'print 5'     if you use Python 2.x, nor the exec neither the print is a function there
    exec('print(5)\nprint(6)')  # prints 5{newline}6.
    exec('if True: print(6)')  # prints 6.
    exec('5')                 # does nothing and returns nothing.
  2. eval組み込み関数(ステートメントではない)であり、式を評価して、式が生成する値を返します。例:

    x = eval('5')              # x <- 5
    x = eval('%d + 6' % x)     # x <- 11
    x = eval('abs(%d)' % -100) # x <- 100
    x = eval('x = 5')          # INVALID; assignment is not an expression.
    x = eval('if 1: x = 4')    # INVALID; if is a statement, not an expression.
  3. compileexecおよびの下位バージョンですeval。ステートメントや式は実行または評価されませんが、それを実行できるコードオブジェクトを返します。モードは次のとおりです。

    1. compile(string, '', 'eval')実行した場合に実行されるコードオブジェクトを返しますeval(string)。このモードではステートメントを使用できないことに注意してください。(単一の)式のみが有効です。
    2. compile(string, '', 'exec')実行した場合に実行されるコードオブジェクトを返しますexec(string)。ここでは任意の数のステートメントを使用できます。
    3. compile(string, '', 'single')execモードに似ていますが、最初のステートメント以外はすべて無視されます。ことを注意if/ elseその結果と文は単一のステートメントとみなされます。

40
Python 3では、exec()今は実際には関数です。
Tim Pietzcker、2010

2
(ご指摘のexecとおり)はターゲットバージョンのステートメントであるため、これらの括弧を含めるのは欺瞞的in globals, localsです。
マイクグラハム、

2
@MikeGraham exec は括弧をサポートし、Python 2での呼び出しのように機能します
Antti Haapala 2015

2
@AnttiHaapalaは、割り当てが「括弧をサポートする」限り、できるのでx = (y)、それは本当かもしれません。別のステートメント変換関数はprintです。print(1, 2, 3)Python 2と3 の結果を比較します
habnabit

1
@habnabitは好きではない。ここで私の答えの下を読んで驚いてください。
Antti Haapala 2015

50

execはforステートメントであり、何も返しません。evalは式用で、式の値を返します。

式は「何か」を意味し、ステートメントは「何かをする」ことを意味します。


9
2番目の段落は非常に単純化されており、ほとんど嘘になります。式に関数呼び出しが含まれている場合、式は非常に多くのことを実行できます。
Antti Haapala 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.