PythonでPythonコードを含む文字列を実行するにはどうすればよいですか?


357

PythonでPythonコードを含む文字列を実行するにはどうすればよいですか?


5
公平を期すために、他の質問とは異なり、これは重複ではありません。そして、他のものはこれよりはるかに基本的な質問を投稿しました。
DNS

8
もちろん、正解はほとんどの場合「しないでください」です。
ボビンス2009年

23
@S Lott:最近、FAQを読んでいないのですか?「プログラミングの質問に答えるのもまったく問題ありませんが、Jeopardyにいるふりをして、質問の形式でフレーズを書いてください。」これは悪い質問ではありません。+1
デヴィンジャンピエール

49
@ S.Lott:そうではありません。する必要はありません。質問がまだサイトにない場合、それは公正なゲームです(すでに指摘したように、FAQによると)。OPが助けを必要とするかのように、すべての質問に答えてください。彼らはそうしないかもしれませんが、彼らの質問を読む次の人はおそらくそうするでしょう。ちょうど私の2セント。
リザードを請求する

1
それをしないと言っているすべての人に:私は絶対に必要な場合があります。これには分散処理が含まれます。
sudo

回答:


331

ステートメントには、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

ただし、最初のステップは、本当に必要かどうかを自問することです。コードの実行は、通常、最後の手段とすべきです。ユーザーが入力したコードが含まれる可能性がある場合、遅く、醜く、危険です。より高次の関数などの代替案を常に最初に見て、これらがニーズにより適切に対応できるかどうかを確認する必要があります。


1
しかし、「exec」によって実行されるコードのスコープはどうですか?ネストされていますか?
ジョンディナム

21
誰かが「exec」を使用したいという一般的なケースはif s=='foo': x.foo = 42 elif s=='bar': x.bar = 42、etcのようなものexec ("x.%s = 42" % s)です。この一般的なケース(文字列に格納されているオブジェクトの属性にアクセスするだけでよい)の場合、はるかに高速でクリーンで安全な関数がありますgetattr。同じことgetattr(x, s) = 42を意味するように書き込むだけです。
ShreevatsaR 2012

5
execはpythonインタープリターよりも遅いのですか?
Cris Stringfellow 2013

6
@ShreevatsaRという意味setattr(x, s, 42)ですか?私が試しましgetattr(x, 2) = 42たが失敗しましたcan't assign to function call: <string>, line 1
Tanner Semerad 2013年

6
@タナー:うーん。はい、確かsetattr(x, s, 42)に正しい構文です。驚いたことに、そのエラーがキャッチされるまでに長い時間がかかりました。とにかく、ポイントはということであるgetattrsetattrする代わりにしているexecあなたが望むすべてが任意のメンバーを取得するときに、文字列で見上げました。
ShreevatsaR 2013年

68

この例では、文字列は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()

1
そのようにstdoutとstderrを入れ替えると、私はとても緊張します。これは、大きなセキュリティ問題を引き起こす可能性があるように見えます。それを回避する方法はありますか?
Narcolapser

1
@Narcolapser exec(コード文字列が信頼できるソースからのものであることがわかっている場合を除いて)を使用することについて、まったく心配する必要あります。
Bruno desthuilliers

27

evalexecは正しい解決策であり、より安全な方法で使用できます。

で説明したように、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

本質的には、コードが実行される名前空間を定義しています。


9
evalを安全にすることはできません 。Evalは本当に危険です。私からコードを取得して評価すると、Pythonプログラムをsegfaultできます。ゲームオーバー。
Ned Batchelder 2013

3
@ v.oddou「evalとexecは安全な方法で使用できます」というアランの声明に応えていました。これは誤りです。誰かが「bashは安全な方法で使用できる」と言ったとしても、それは誤りです。バッシュは危険です。それは必要な危険ですが、それでも危険です。evalを安全にすることができると主張することは単に間違っています。
Ned Batchelder、2015年

1
@NedBatchelderはい、確かに。そして、あなたが指すリンクは良い資料です。力には責任が伴うので、ポイントは単にevalの潜在的な力を認識することです。そして、power = dangerと決定した場合。
v.oddou 2015年

3
@NedBatchelder Pythonで記述されたコードの多くの部分も危険である可能性がありますが、なぜ、evalまたは次のexecように使用することを想定しているのexec(input("Type what you want"))ですか?プログラムが計算の結果としてプロシージャまたは関数を書く場合が多くあります。結果として得られる関数は、優れた適切に作成されたプログラムの他の部分と同じくらい安全かつ高速です(一度評価されると)。を含む安全でないプログラムexecexec、プログラムに新しい特権を与えないため、それ自体が損傷を与える安全でないプログラムほど危険ではありません。
Thomas Baruchel

1
@ThomasBaruchel再び、私のポイントはevalまたはexecを安全にすることができるという考えに対抗することです。特に、この回答は、グローバルとローカルを制御することで、それらを安全に使用できるようになると主張しています。それは誤りです。execとevalを使用するときはいつでも、実行されているコードを正確に知る必要があります。そうしないと、危険な操作が可能になります。
Ned Batchelder 2016年

21

バージョン3からexecの機能であることを忘れないでください!
したがって、常にのexec(mystring)代わりに使用してくださいexec mystring


11

eval()表現用ですが、機能しeval('x+1')ますが、eval('x=1')たとえば機能しません。その場合は、を使用することをお勧めしますexec。さらに良い方法は、より良い解決策を見つけることです:)


11

避けexeceval

使用execしてevalPythonで非常にひんしゅくを買うされます。

より良い代替案があります

上の答えから(私の強調):

ステートメントにはを使用しますexec

式の値が必要な場合は、を使用してくださいeval

ただし、最初にすべきことは、本当に必要かどうかを自問することです。コードの実行は、通常、最後の手段とすべきです。ユーザーが入力したコードを含めることができる場合、遅く、醜く、危険です。より高次の関数などの代替案を常に最初に見て、ニーズを満たすことができるかどうかを確認する必要があります。

代替への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か月後にこのコードをデバッグまたは拡張する可能性がある場合は、それを直接困難にすることになります。


「2つのアンダースコアを使用できない場合、害を及ぼすことはできないと思います」-二重のアンダースコアを含む文字列を作成し、その文字列をevalで呼び出すことができます。
Stanley Bak 2016年

あなたがコードジェネレータやジョブランナーなどを書いているのでなければ、良いアドバイスです...ここのほとんどの人々はおそらくそうしているでしょう。
Erik Aronesty、

構成ファイル(cfg.yaml)から相対パスをインポートする必要があります:reldir : ../my/dir/ 、およびreldir = cfg[reldir]。ただし、このpythonコードはWindowsとLinuxの両方で実行されるので、さまざまなオペレーティングシステムのパスディバイダーに合わせて調整する必要があります。いずれか\\ または/。だから私reldir : os.path.join('..','my','dir')は設定ファイルで使用します。ただし、これreldirはこのリテラル文字列であり、評価されないため、でファイルを開くことができませんreldir。提案はありますか?
マリー。P.

9

次のIDLEセッションのように、execを使用してコードを実行します。

>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']

4

1
これは通常のpythonでは機能しません。少なくともではないのpython 3で
トーマスAhle

6

他の人が述べたように、それは「exec」です。

ただし、コードに変数が含まれている場合は、「グローバル」を使用してコードにアクセスし、コンパイラが次のエラーを発生させないようにすることもできます。

NameError:名前 'p_variable'が定義されていません

exec('p_variable = [1,2,3,4]')
global p_variable
print(p_variable)


4

それは言及する価値があります、それはあなたがPythonファイルを呼び出したいのであればexec呼ばれる兄弟が存在するexecfileことです。ひどいIDEが含まれているサードパーティのパッケージで作業していて、それらのパッケージの外でコーディングしたい場合、これは時々良いことです。

例:

execfile('/path/to/source.py)'

または:

exec(open("/path/to/source.py").read())



1

私はかなりの数のことを試しましたが、機能するのは次のものだけでした:

temp_dict = {}
exec("temp_dict['val'] = 10") 
print(temp_dict['val'])

出力:

10


0

最も論理的な解決策は、組み込みのeval()関数を使用することです。別の解決策は、その文字列を一時的なpythonファイルに書き込んで実行することです。


0

わかりました..これは正確な答えではないことを知っていますが、私がそうであったようにこれを見ている人々のためのノートかもしれません。さまざまなユーザー/顧客向けに特定のコードを実行したいが、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を実行します


1
セキュリティをどのように管理しましたか?顧客がこの特権を乱用しないことをどのようにして知っていますか?
JSBach
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.