私がPythonで読んでいる本では、eval(input('blah'))
というコードを使い続けています。
私はドキュメンテーションを読み、それを理解していますが、それがinput()
関数をどのように変更するのかまだわかりません。
それは何をするためのものか?誰かが説明できますか?
Eval関数は、Pythonプログラムが自分自身の中でPythonコードを実行することを可能にします。
evalの例(インタラクティブシェル):
>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1
eval()
は文字列をコードとして解釈します。非常に多くの人々がこれを使用することについてあなたに警告した理由は、ユーザーがコンピュータ上でコードを実行するためのオプションとしてこれを使用できるからです。 eval(input())
とos
がインポートされている場合は、input()
os.system('rm -R *')
と入力すると、ホームディレクトリ内のすべてのファイルが削除されます。 (あなたがUNIXシステムを持っていると仮定します)。 eval()
を使うことはセキュリティホールです。文字列を他の形式に変換する必要がある場合は、int()
のようにそれを行うことを試みてください。
ここにはたくさんの良い答えがありますが、その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]
Python 2.xではinput(...)
はeval(raw_input(...))
と同等ですが、Python 3.xではraw_input
はinput
と改名されました。混乱を招くと思われます(おそらくPython 2.xのinput
のドキュメントを見ていたのでしょう)。さらに、eval(input(...))
はPython 3.xでは問題なく動作しますが、Python 2ではTypeError
が発生します。
この場合、eval
は、input
から返された文字列を式に変換して解釈するために使用されます。一般にこれは悪い習慣と考えられています。
eval()
は渡された文字列をPythonの式として評価し、結果を返します。たとえば、eval("1 + 1")
は式"1 + 1"
を解釈して実行し、結果(2)を返します。
あなたが混乱するかもしれない1つの理由はあなたが引用したコードが間接参照のレベルを含むからです。内部関数呼び出し(入力)が最初に実行されるので、ユーザーは "blah"プロンプトを見ます。それらが "1 + 1"(明確にするために引用符を付けてください。あなたのプログラムを実行するときにそれらをタイプしないでください)で反応すると想像してみましょう。そして入力関数はその文字列を返します。結果(2)を返します。
Evalについてもっと読んでください ここ 。
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を返します。
行を読んでそれを解釈するという誤解を招くような例かもしれません。
eval(input())
を試して"1+1"
とタイプしてください - これは2
を表示するはずです。 Evalは式を評価します。
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'}
私はこの質問に答えるのが遅れています、しかし誰もその質問に明確な答えを与えるようには思えません。
ユーザーが数値を入力すると、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
評価文字列を単純なリテラルに限定したい場合のもう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と似ていますがより強力な形式でのシリアル化に使用できます。