私はPythonコードの動的評価を検討しており、eval()
およびcompile()
関数とexec
ステートメントに出くわしました。
eval
との違い、およびexec
さまざまなモードがどのようにcompile()
適合するかを誰かが説明できますか?
私はPythonコードの動的評価を検討しており、eval()
およびcompile()
関数とexec
ステートメントに出くわしました。
eval
との違い、およびexec
さまざまなモードがどのようにcompile()
適合するかを誰かが説明できますか?
回答:
基本的eval
に使用される評価 uate単一動的に生成されたPythonの式を、とexec
するために使用されるEXECのみ、その副作用のUTE動的に生成されたPythonコード。
eval
そしてexec
これら2つの違いがあります。
eval
のみ受け付ける単一の発現を、exec
ループ、:Pythonの文有するコードブロック取ることができtry: except:
、class
及び関数/メソッドのdef
ようにinitionsとします。
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
は関数内の副作用に使用される関数に対して異なる種類のコードオブジェクトを生成する必要があったため、ステートメントでした。
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
としてのいずれかで実行されるプログラム/発現受け入れる両方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
utedコードが作成する変数をキャプチャするためにも使用できます。
>>> 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
そのでexcept
、else
そして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
。
したがって、機能とそのモードの最大の違いはexec
、eval
実際にはcompile
その機能とモードに由来します。
ソースコードをバイトコードにコンパイルすることに加えて、抽象構文ツリー(Pythonコードの解析ツリー)のオブジェクトへのコンパイルをcompile
サポートします。そして、ソースコードを抽象構文ツリーに入れます(これはPythonで記述され、を呼び出すだけです)。これらは、複雑なケースではコードをテキスト行ではなくノードのツリーとして処理する方が簡単な場合が多いため、ソースコードをオンザフライで変更する場合や動的コード作成などに使用されます。code
ast.parse
compile(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を調べてソースコードを調べるeval
とexec
、これは非常に明白です。どちらもPyEval_EvalCode
同じ引数で呼び出しますが、唯一の違いはexec
明示的にを返すことNone
です。
exec
Python 2とPython 3の構文の違いPython 2の主な違いの1つは、それexec
がステートメントでeval
あり、組み込み関数であることです(どちらもPython 3の組み込み関数です)。exec
Python 2の公式構文がであることはよく知られている事実ですexec code [in globals[, locals]]
。
2対3のPythonの大半とは異なりポーティング ガイドは 思え 示唆し、exec
CPythonの2の文では、という構文で使用することができルックス 正確のようなexec
Pythonの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
、それ以外locals
のexec
ステートメントに渡されなかった場合、はcode
解釈されますタプルの2番目と3番目の要素がそれぞれglobals
andで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との互換性を提供します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
代わりにループを使用してください)。
42
も式であり@
、デコレータとしては使用できません。
decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE
。つまり、任意の式をデコレータとして使用することはできません。(ドットで区切られた)識別子と、それに続くオプションの呼び出し引数のみを使用できます。
a = b = c
はその右辺と同様に完全に有効なステートメントですb = c
-これは式ではありません。
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.
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.
compile
exec
およびの下位バージョンですeval
。ステートメントや式は実行または評価されませんが、それを実行できるコードオブジェクトを返します。モードは次のとおりです。
compile(string, '', 'eval')
実行した場合に実行されるコードオブジェクトを返しますeval(string)
。このモードではステートメントを使用できないことに注意してください。(単一の)式のみが有効です。compile(string, '', 'exec')
実行した場合に実行されるコードオブジェクトを返しますexec(string)
。ここでは任意の数のステートメントを使用できます。compile(string, '', 'single')
exec
モードに似ていますが、最初のステートメント以外はすべて無視されます。ことを注意if
/ else
その結果と文は単一のステートメントとみなされます。exec()
今は実際には関数です。
exec
とおり)はターゲットバージョンのステートメントであるため、これらの括弧を含めるのは欺瞞的in globals, locals
です。
exec
は括弧をサポートし、Python 2での呼び出しのように機能します。
x = (y)
、それは本当かもしれません。別のステートメント変換関数はprint
です。print(1, 2, 3)
Python 2と3 の結果を比較します
execはforステートメントであり、何も返しません。evalは式用で、式の値を返します。
式は「何か」を意味し、ステートメントは「何かをする」ことを意味します。
[i for i in globals().values() if hasattr(i, '__call__')][0]
文または式は?式だったのに、なぜ@
デコレータとして使えないのですか?