Pythonのeval()は何をしますか?


306

私がPythonで読んでいる本では、コードを使い続けています eval(input('blah'))

ドキュメントを読んで理解しましたが、それによってinput()機能がどのように変わるかはまだわかりません。

それは何をするためのものか?誰かが説明できますか?


4
Eval関数は、Pythonコードとして渡された文字列(引数)を実行して解釈しようとします。x = 1 print(eval( 'x + 1'))上記のコードの出力は2になります。このようなアプローチの不利な点は、ユーザーがコードを書くことから独立し、混乱を招く可能性があることです。 eval関数でグローバルパラメータとローカルパラメータを渡して、多くの変数とメソッドにアクセスする。
ATIF IBAD KHAN 2017

回答:


276

関数evalを使用すると、Pythonプログラム自体でPythonコードを実行できます。

evalの例(インタラクティブシェル):

>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1

25
これは簡単な例ですが、ユーザーに任意のコマンドを入力させ、Pythonにそれを実行させることができます。したがって、ユーザーにコマンド文字列を入力させ、それをpythonにコードとして実行させることができます。したがって、たとえばeval( "__ import __( 'os')。remove( 'file')")のようになります。
BYS2

60
あなたがそれを必要とするまで、それは役に立たないようです。codepad.orgなどのサイトで使用され、テスト環境でスクリプトを実行できます。eval()は、非常に動的なコードの実行にも使用できますが、使用する前に、セキュリティとパフォーマンスのリスクを十分に理解しておく必要があります。
ジョージカミンズ

6
@GeorgeCummins、codepad.org使用していないeval、またそれはそれはと何を行うことができますeval
マイクグラハム

16
@GeorgeCummins:codepag.orgはすべてをサンドボックスで実行します。悪質なコードが悪いことをするのを防ぐために仮想マシンでptraceチェックを備えたchroot jailを実行します。単純な評価よりもはるかに複雑です。また、evalはPython固有です。コードパッドは多数の言語をサポートしています。
FogleBird

4
@GeorgeCummins、コードパッドは非常に複雑なシステムを実行して、任意のプログラムを安全に実行します。evalは、安全でないことを除いて、単一の式しか評価できないため、コードパッドのようにプログラム全体を実行することはできません。
マイクグラハム

165

eval()文字列をコードとして解釈します。非常に多くの人々がこれを使用することについてあなたに警告した理由は、ユーザーがコンピュータ上でコードを実行するオプションとしてこれを使用できるためです。あなたが持っている場合eval(input())os、インポート、人はに入力することができinput() os.system('rm -R *')、あなたのホームディレクトリ内のすべてのファイルを削除することになります。(あなたがUNIXシステムを持っていると仮定します)。使用eval()はセキュリティホールです。文字列を他の形式に変換する必要がある場合は、そのようなことを行うようにしてくださいint()


14
つまり、evalwith input()はセキュリティホールです。input()evalステートメントの中に入れないでください。大丈夫です。
ローマー2015

19
@Rohmerの安全でないデータは、コンソール入力からだけでなく、Webリクエスト、フォーム入力フィールド、ファイルの読み取りなど、あらゆる場所から発生する可能性があります。自分でファイルを作成した場合でも、信頼できないソースからの入力が含まれている可能性があります。したがってeval、多くの場合、セキュリティの問題です。
sanderd17

3
以来、input通常のコンソールからデータを受け取り、ユーザは、単にプログラムを終了して入力することができrm -R *...とにかく
CZ

63

ここには良い答えがたくさんありeval()ますが、そのglobalslocalskwargsのコンテキストでの使用については説明されていませんeval(expression, globals=None, locals=None)(つまり、eval こちらのドキュメントを参照)。

これらは、関数を介して使用できる関数を制限するために使用できますeval。たとえば、あなたは通訳新鮮なのpythonをアップロードする場合locals()globals()、このように同じと見て何かになります:

>>>globals()
{'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__doc__': None,
 '__spec__': None, '__builtins__': <module 'builtins' (built-in)>,
 '__package__': None, '__name__': '__main__'}

builtinsモジュールには、システムに重大な損傷を与える可能性のある機能が確かにあります。しかし、利用可能にしたくないものはすべてブロックすることが可能です。例を見てみましょう。システムで使用可能なコアのドメインを表すリストを作成するとします。私には8つのコアがあるので、リストが必要です[1, 8]

>>>from os import cpu_count
>>>eval('[1, cpu_count()]')
[1, 8]

同様にすべて__builtins__利用可能です。

>>>eval('abs(-1)')
1

OK。そこで、公開したい1つの関数と、公開したくない1つの(はるかに複雑になる可能性がある)メソッドの例を確認します。だからすべてをブロックしましょう。

>>>eval('[1, cpu_count()]', {'__builtins__':None}, {})
TypeError: 'NoneType' object is not subscriptable

すべての__builtins__機能を効果的にブロックし、システムに一定レベルの保護をもたらしました。この時点で、公開したい関数を追加し始めることができます。

>>>from os import cpu_count
>>>exposed_methods = {'cpu_count': cpu_count}
>>>eval('cpu_count()', {'__builtins__':None}, exposed_methods)
8
>>>eval('abs(cpu_count())', {'__builtins__':None}, exposed_methods)
TypeError: 'NoneType' object is not subscriptable

これで、cpu_count不要なものをすべてブロックしながら、関数を使用できるようになりました。私の意見では、これは非常に強力であり、一般的な実装ではなく、明らかに他の回答の範囲からです。このような使い方はたくさんありますが、正しく扱えば、個人的にevalは安全に大いに活用できると思います。

NB

これらのkwargs優れた点は、コードの省略形を使い始めることができることです。インポートしたテキストを実行するパイプラインの一部としてevalを使用するとします。テキストは正確なコードである必要はありません。テンプレートファイル形式に従っていても、好きなように実行できます。例えば:

>>>from os import cpu_count
>>>eval('[1,cores]', {'__builtins__': None}, {'cores': cpu_count()})
[1, 8]

29

Python 2.xはとinput(...)同等ですがeval(raw_input(...))、Python 3.xのraw_input名前がに変更さinputれました。混乱を招いたと思われます(おそらくinputPython 2.xのドキュメントを参照していました)。さらに、eval(input(...))Python 3.xでは問題なく動作しますがTypeError、Python 2ではが発生します。

この場合eval、から返された文字列をinput式に変換して解釈するために使用されます。一般にこれは悪い習慣だと考えられています。


または、Python 3.xの本で、2.xでinputraw_inputが行われたかを示しています。
dan04

1
ええ、私が最初の答えを書いた後に私に起こりました、そしてそれは明らかに事実です。
zeekay

6

行を読んでそれを解釈するという、誤解を招く例かもしれません。

試しeval(input())て入力してください"1+1"-これは印刷されるはず2です。Evalは式を評価します。


引用符の間に入力する必要があるのはなぜですか?入力は文字列を取得し、それをコードを実行するのではなくevalに渡すため、単純に1 + 1 ...と入力すれば問題ないはずです。
JC Rocamonde 2015

問題は、P2.xと3.xを混在させていることです。Python 2ではコードは機能しますが、2回evalしても意味がありません。Python 3ではそうではなく、文字列を返します。
JCロカモンデ2015

6

eval()渡された文字列をPython式として評価し、結果を返します。たとえばeval("1 + 1")、式"1 + 1"を解釈して実行し、結果を返します(2)。

混乱するかもしれない理由の1つは、引用したコードに一定レベルの間接参照が含まれているためです。内部関数呼び出し(入力)が最初に実行されるため、ユーザーには「何とか」のプロンプトが表示されます。それらが「1 + 1」(わかりやすくするために追加した引用符、プログラムの実行時に入力しないでください)で応答すると想像してみてください。入力関数はその文字列を返し、その文字列を解釈する外部関数(eval)に渡されます。結果(2)を返します。

evalの詳細については、こちらをご覧ください


6

eval()は、その名前が示すように、渡された引数を評価します。

raw_input()現在input()、Python 3.xバージョンです。したがって、の最も一般的な使用例は、Pythonの2.xバージョンで提供されていeval()た機能をinput()提供するための使用です。raw_inputはユーザーが入力したデータを文字列として返し、inputは入力されたデータの値を評価して返しました。

eval(input("bla bla")) したがって、の機能を複製します input()、2.x、つまりユーザーが入力したデータを評価します。

つまりeval()、渡された引数を評価してeval('1 + 1')2を返します。


6

の便利なアプリケーションの1つはeval()、文字列からPython式を評価することです。たとえば、辞書のファイル文字列表現からロードします。

running_params = {"Greeting":"Hello "}
fout = open("params.dat",'w')
fout.write(repr(running_params))
fout.close()

変数として読み取って編集します。

fin = open("params.dat",'r')
diction=eval(fin.read())
diction["Greeting"]+="world"
fin.close()
print diction

出力:

{'Greeting': 'Hello world'}

7
これは何を尋ねる質問にどのように答えevalますか?
jkd 2015年

4

私はこの質問に答えるのが遅いですが、誰も質問に明確な答えを出すようには見えません。

ユーザーが数値を入力するinput()と、文字列が返されます。

>>> input('Enter a number: ')
Enter a number: 3
>>> '3'
>>> input('Enter a number: ')
Enter a number: 1+1
'1+1'

したがって、eval()文字列である戻り値(または式)を評価し、整数/浮動小数点数を返します。

>>> eval(input('Enter a number: '))
Enter a number: 1+1
2
>>> 
>>> eval(input('Enter a number: '))
Enter a number: 3.14
3.14

もちろん、これは悪い習慣です。int()または、この場合のfloat()代わりに使用する必要がありますeval()

>>> float(input('Enter a number: '))
Enter a number: 3.14
3.14

3

評価文字列を単純なリテラルに制限する場合のもう1つのオプションは、を使用することast.literal_eval()です。いくつかの例:

import ast

# print(ast.literal_eval(''))          # SyntaxError: unexpected EOF while parsing
# print(ast.literal_eval('a'))         # ValueError: malformed node or string
# print(ast.literal_eval('import os')) # SyntaxError: invalid syntax
# print(ast.literal_eval('1+1'))       # 2: but only works due to a quirk in parser
# print(ast.literal_eval('1*1'))       # ValueError: malformed node or string
print(ast.literal_eval("{'a':1}"))     # {'a':1}

ドキュメントから:

式ノードまたはPythonリテラルまたはコンテナー表示を含む文字列を安全に評価します。提供される文字列またはノードはは、文字列、バイト、数値、タプル、リスト、辞書、セット、ブール、およびなしのPythonリテラル構造構成されます。

これは、自分で値を解析する必要なしに、信頼できないソースからのPython値を含む文字列を安全に評価するために使用できます。演算子やインデックスなど、複雑な式を任意に評価することはできません

なぜそれがそれほど制限されているのかについては、メーリングリストから:

リテラルを含む演算子式を許可することは可能ですが、現在の実装よりもはるかに複雑です。単純な実装は安全ではありません。基本的に無制限にCPUとメモリの使用を誘発することができます( "9 ** 9 ** 9"または "[None] * 9 ** 9"を試してください)。

有用性に関しては、この関数は、repr()によって文字列化されたリテラル値とコンテナーを「読み戻す」のに役立ちます。これは、たとえば、JSONに似ているがより強力な形式でのシリアル化に使用できます。


1
ast.literal_evalあなたの'1+1'例とは逆に、は演算子をサポートしていません。それでも、リスト、数値、文字列などをサポートしているため、一般的なevalユースケースの代替として適しています。
ベンジミン

@benjiminああ、そうです-1 + 1を受け入れるのはただの癖です!stackoverflow.com/questions/40584417/...
ブライアン・バーンズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.