PythonでPythonコードを含む文字列を実行するにはどうすればよいですか?
PythonでPythonコードを含む文字列を実行するにはどうすればよいですか?
回答:
ステートメントには、exec(string)
(Python 2/3)またはexec string
(Python 2)を使用します。
>>> mycode = 'print "hello world"'
>>> exec(mycode)
Hello world
式の値が必要な場合は、次を使用しますeval(string)
。
>>> x = eval("2+2")
>>> x
4
ただし、最初のステップは、本当に必要かどうかを自問することです。コードの実行は、通常、最後の手段とすべきです。ユーザーが入力したコードが含まれる可能性がある場合、遅く、醜く、危険です。より高次の関数などの代替案を常に最初に見て、これらがニーズにより適切に対応できるかどうかを確認する必要があります。
if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42
、etcのようなものexec ("x.%s = 42" % s)
です。この一般的なケース(文字列に格納されているオブジェクトの属性にアクセスするだけでよい)の場合、はるかに高速でクリーンで安全な関数がありますgetattr
。同じことgetattr(x, s) = 42
を意味するように書き込むだけです。
setattr(x, s, 42)
ですか?私が試しましgetattr(x, 2) = 42
たが失敗しましたcan't assign to function call: <string>, line 1
setattr(x, s, 42)
に正しい構文です。驚いたことに、そのエラーがキャッチされるまでに長い時間がかかりました。とにかく、ポイントはということであるgetattr
とsetattr
する代わりにしているexec
あなたが望むすべてが任意のメンバーを取得するときに、文字列で見上げました。
この例では、文字列はexec関数を使用してコードとして実行されます。
import sys
import StringIO
# create file-like string to capture output
codeOut = StringIO.StringIO()
codeErr = StringIO.StringIO()
code = """
def f(x):
x = x + 1
return x
print 'This is my output.'
"""
# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr
exec code
# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
print f(4)
s = codeErr.getvalue()
print "error:\n%s\n" % s
s = codeOut.getvalue()
print "output:\n%s" % s
codeOut.close()
codeErr.close()
exec
(コード文字列が信頼できるソースからのものであることがわかっている場合を除いて)を使用することについて、まったく心配する必要があります。
eval
とexec
は正しい解決策であり、より安全な方法で使用できます。
で説明したように、Pythonのリファレンスマニュアルと明確に説明し、このチュートリアル、eval
およびexec
機能は、ユーザーがグローバルとローカル関数や変数が利用可能であるかを指定できるようにする2つの追加のパラメータを取ります。
例えば:
public_variable = 10
private_variable = 2
def public_function():
return "public information"
def private_function():
return "super sensitive information"
# make a list of safe functions
safe_list = ['public_variable', 'public_function']
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
# add any needed builtins back in
safe_dict['len'] = len
>>> eval("public_variable+2", {"__builtins__" : None }, safe_dict)
12
>>> eval("private_variable+2", {"__builtins__" : None }, safe_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'private_variable' is not defined
>>> exec("print \"'%s' has %i characters\" % (public_function(), len(public_function()))", {"__builtins__" : None}, safe_dict)
'public information' has 18 characters
>>> exec("print \"'%s' has %i characters\" % (private_function(), len(private_function()))", {"__builtins__" : None}, safe_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'private_function' is not defined
本質的には、コードが実行される名前空間を定義しています。
eval
または次のexec
ように使用することを想定しているのexec(input("Type what you want"))
ですか?プログラムが計算の結果としてプロシージャまたは関数を書く場合が多くあります。結果として得られる関数は、優れた適切に作成されたプログラムの他の部分と同じくらい安全かつ高速です(一度評価されると)。を含む安全でないプログラムexec
はexec
、プログラムに新しい特権を与えないため、それ自体が損傷を与える安全でないプログラムほど危険ではありません。
exec
てeval
exec
してeval
Pythonで非常にひんしゅくを買うされます。上の答えから(私の強調):
ステートメントにはを使用します
exec
。式の値が必要な場合は、を使用してください
eval
。ただし、最初にすべきことは、本当に必要かどうかを自問することです。コードの実行は、通常、最後の手段とすべきです。ユーザーが入力したコードを含めることができる場合、遅く、醜く、危険です。より高次の関数などの代替案を常に最初に見て、ニーズを満たすことができるかどうかを確認する必要があります。
文字列の名前を持つ変数の値を設定および取得する
[
eval
]は機能しますが、プログラム自体に意味のある変数名を使用することは一般に推奨されません。代わりに、dictを使用してください。
http://lucumr.pocoo.org/2011/2/1/exec-in-python/(強調鉱山)
PythonはPHPではありません
他の言語では動作が異なるため、Pythonイディオムを回避しようとしないでください。名前空間がPythonに含まれているのには理由があり、ツールが提供されるからといって、
exec
そのツールを使用する必要があるわけではありません。
http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html(強調鉱山)
したがって、すべてのグローバルとビルトインを削除しても、evalは安全ではありません。
eval()を保護するこれらすべての試みの問題は、それらがブラックリストであることです。危険な可能性のあるものを明示的に削除します。リストから1つだけの項目が残っている場合、システムを攻撃できるため、これは敗戦です。
では、evalを安全にすることはできますか?言いにくい。この時点で、ダブルアンダースコアを使用できない場合は害を及ぼさないので、ダブルアンダースコアを含む文字列を除外すると安全だと私は推測しています。多分...
http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.htmlから(鉱山を強調):
まず、
exec
人間がコードを読みにくくします。何が起こっているのかを理解するために、コードを読み取るだけでなく、コードを読み取って、生成される文字列を理解し、仮想コードを読み取る必要があります。したがって、チームで作業している場合や、オープンソースソフトウェアを公開している場合、またはStackOverflowなどのどこかで助けを求めている場合、他の人があなたを助けることが困難になります。そして、6か月後にこのコードをデバッグまたは拡張する可能性がある場合は、それを直接困難にすることになります。
cfg.yaml
)から相対パスをインポートする必要があります:reldir : ../my/dir/
、およびreldir = cfg[reldir]
。ただし、このpythonコードはWindowsとLinuxの両方で実行されるので、さまざまなオペレーティングシステムのパスディバイダーに合わせて調整する必要があります。いずれか\\
または/
。だから私reldir : os.path.join('..','my','dir')
は設定ファイルで使用します。ただし、これreldir
はこのリテラル文字列であり、評価されないため、でファイルを開くことができませんreldir
。提案はありますか?
それは言及する価値があります、それはあなたがPythonファイルを呼び出したいのであればexec
呼ばれる兄弟が存在するexecfile
ことです。ひどいIDEが含まれているサードパーティのパッケージで作業していて、それらのパッケージの外でコーディングしたい場合、これは時々良いことです。
例:
execfile('/path/to/source.py)'
または:
exec(open("/path/to/source.py").read())
わかりました..これは正確な答えではないことを知っていますが、私がそうであったようにこれを見ている人々のためのノートかもしれません。さまざまなユーザー/顧客向けに特定のコードを実行したいが、exec / evalも回避したかった。私は最初に各ユーザーのデータベースにコードを保存し、上記を実行することを検討しました。
結局、「customer_filters」フォルダ内のファイルシステムにファイルを作成し、「imp」モジュールを使用しました。その顧客にフィルタが適用されていない場合は、そのまま実行されました
import imp
def get_customer_module(customerName='default', name='filter'):
lm = None
try:
module_name = customerName+"_"+name;
m = imp.find_module(module_name, ['customer_filters'])
lm = imp.load_module(module_name, m[0], m[1], m[2])
except:
''
#ignore, if no module is found,
return lm
m = get_customer_module(customerName, "filter")
if m is not None:
m.apply_address_filter(myobj)
したがって、customerName = "jj"は、customer_filters \ jj_filter.pyファイルからapply_address_filterを実行します