web-dev-qa-db-ja.com

Pythonのeval()は何をするの? 

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

私はドキュメンテーションを読み、それを理解していますが、それがinput()関数をどのように変更するのかまだわかりません。

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

246
Billjk

Eval関数は、Pythonプログラムが自分自身の中でPythonコードを実行することを可能にします。

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

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

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

135
CoffeeRain

ここにはたくさんの良い答えがありますが、そのglobalsおよびlocals kwargsの文脈でのeval()の使用、すなわち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を安全に大きな価値があると考えることができると思います。

N.B.

これらのkwargsについて他にクールなことは、あなたのコードのために速記を使い始めることができるということです。インポートされたテキストを実行するためにパイプラインの一部としてevalを使用するとしましょう。テキストは正確なコードを持っている必要はありません、それはあるテンプレートファイルフォーマットに従うことができて、そしてあなたが望むものを実行することができます。例えば:

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

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

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

27
zeekay

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

あなたが混乱するかもしれない1つの理由はあなたが引用したコードが間接参照のレベルを含むからです。内部関数呼び出し(入力)が最初に実行されるので、ユーザーは "blah"プロンプトを見ます。それらが "1 + 1"(明確にするために引用符を付けてください。あなたのプログラムを実行するときにそれらをタイプしないでください)で反応すると想像してみましょう。そして入力関数はその文字列を返します。結果(2)を返します。

Evalについてもっと読んでください ここ

6
Marc Cohen

eval()は、その名の通り、渡された引数を評価します。

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

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

簡単に言うと、eval()は渡された引数を評価するので、eval('1 + 1')は2を返します。

5
Rubal

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

eval(input())を試して"1+1"とタイプしてください - これは2を表示するはずです。 Evalは式を評価します。

5
hburde

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'}
4
Nikolay Frick

私はこの質問に答えるのが遅れています、しかし誰もその質問に明確な答えを与えるようには思えません。

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

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

そのため、eval()は文字列である戻り値(または式)を評価し、integer/floatを返します。

>>> 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
Calvin Kim

評価文字列を単純なリテラルに限定したい場合のもう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}

docs :から

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

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

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

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

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

2
Brian Burns