파이썬에서 파이썬 코드를 포함하는 문자열을 어떻게 실행합니까?


357

파이썬에서 파이썬 코드를 포함하는 문자열을 어떻게 실행합니까?


5
공정하게 말하면 다른 질문과 달리이 질문은 중복되지 않습니다. 그리고 다른 사람들은 이것보다 훨씬 더 기본적인 질문을 게시했습니다.
DNS

8
물론 정답은 거의 항상“하지 마십시오!”입니다.
bobince 2016 년

23
@에스. 로트 : 최근 FAQ를 읽지 않았습니까? "자신의 프로그래밍 질문을하고 답하는 것도 완벽하지만, 당신이 Jeopardy 인 척 : 질문의 형태로 표현하십시오." 이것은 나쁜 질문이 아닙니다. +1
Devin Jeanpierre 2016 년

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'에 의해 실행되는 코드의 범위는 어떻습니까? 중첩되어 있습니까?
jondinham

21
누군가가 'exec'를 사용하려는 일반적인 경우는 다음과 같이 if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42쓸 수 있습니다 exec ("x.%s = 42" % s). (당신은 단지 문자열에 저장된 객체의 속성에 접근 할 필요)이 일반적인 경우를 들어, 더 빠르게, 더 깨끗하고 안전 기능이 getattr바로 쓰기 : getattr(x, s) = 42같은 일을 의미.
ShreevatsaR

5
exec는 파이썬 인터프리터보다 어떻게 느립니까?
Cris Stringfellow

6
@ShreevatsaR은 무슨 뜻 setattr(x, s, 42)인가요? 시도 getattr(x, 2) = 42하고 실패했습니다can't assign to function call: <string>, line 1
Tanner Semerad

6
@Tanner : 흠. 그렇습니다 setattr(x, s, 42). 올바른 구문입니다. 오류가 발생하는 데 시간이 오래 걸린다는 사실에 놀랐습니다. 어쨌든, 요점은 것입니다 getattrsetattr대안이다 exec당신이 원하는 모든 임의 회원을 얻을 때, 문자열에 의해 보였다.
ShreevatsaR

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

eval그리고 exec올바른 솔루션이며, 그들은이에서 사용할 수있는 안전한 방법.

에서 설명하고있는 바와 같이 파이썬의 참조 설명서를 명확하게 설명 튜토리얼의 evalexec기능은 사용자가 글로벌 및 지역 함수와 변수가 사용할 수있는 지정할 수있는 두 개의 추가 매개 변수를.

예를 들면 다음과 같습니다.

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
평가판을 안전하게 만들 수는 없습니다 : 평가판은 실제로 위험 합니다. 나에게서 코드를 가져 와서 평가하면 파이썬 프로그램을 segfault 할 수 있습니다. 게임 끝.
Ned Batchelder

3
@ v.oddou 나는 alan의 진술에 답했다. "eval과 exec는 안전한 방법으로 사용될 수있다." 이것은 거짓입니다. 누군가가 "안전한 방식으로 bash를 사용할 수있다"고 말한 경우에도 마찬가지입니다. 배쉬는 위험하다. 필요한 위험이지만 그럼에도 불구하고 위험합니다. 평가를 안전하게 할 수 있다고 주장하는 것은 단순히 잘못입니다.
Ned Batchelder 2016 년

1
@NedBatchelder 그렇습니다. 그리고 당신이 가리키는 링크는 좋은 자료입니다. 힘은 책임이되므로 요점은 단순히 평가의 잠재적 힘을 인식하는 것입니다. 그리고 우리가 그 힘 = 위험을 결정한다면.
v.oddou

3
@NedBatchelder 파이썬으로 작성된 많은 코드 조각들도 위험 할 수 있지만 왜 그렇게 가정 eval하거나 exec사용하려고 exec(input("Type what you want"))합니까? 프로그램이 계산의 결과로 프로시 저나 함수를 작성할 수있는 경우가 많습니다. 결과적으로 작성된 기능은 훌륭하고 잘 작성된 프로그램의 다른 부분과 마찬가지로 안전하고 빠릅니다 (한 번 평가). 안전하지 않은 프로그램이 포함 된 안전하지 않은 프로그램 exec은 프로그램에 exec새로운 권한을 부여하지 않으므로 자체적으로 손상을 수행하는 안전하지 않은 프로그램보다 위험 하지 않습니다.
Thomas Baruchel

1
@ThomasBaruchel은 다시 말하지만 eval 또는 exec를 안전하게 만들 수 있다는 개념에 반대합니다. 특히,이 답변은 지구본과 지역 주민을 통제하면 안전하게 사용할 수 있다고 주장합니다. 그건 틀렸어 exec와 eval을 사용할 때마다 어떤 코드가 실행되고 있는지 정확하게 알아야합니다. 그렇지 않은 경우 위험한 작업을 수행 할 수 있습니다.
Ned Batchelder

21

버전 3부터는 exec기능 이라는 것을 기억하십시오 !
항상 exec(mystring)대신에 사용하십시오 exec mystring.


11

eval()예를 들어 eval('x+1'), 표현에 불과하지만 작동 eval('x=1')하지 않습니다. 이 경우 사용 exec하는 것이 더 좋거나 더 좋습니다. 더 나은 솔루션을 찾으십시오. :)


11

execeval

사용 exec하여eval파이썬에서 를 것은 매우 찡그림입니다.

더 나은 대안이 있습니다

최고 답변 (강조 광산)에서 :

진술을 위해 exec .

식의 값이 필요한 경우을 사용하십시오 eval.

그러나 첫 번째 단계는 정말로 필요한지 스스로에게 물어보아야합니다. 실행 코드는 일반적으로 최후의 수단이되어야 합니다. 사용자가 입력 한 코드를 포함 할 수 있으면 느리고, 추악하고, 위험합니다. 고차 함수와 같은 대안을 먼저 살펴 보고 이것이 더 나은 요구를 충족시킬 수 있는지 확인해야합니다.

에서 대안 간부 인 / 평가?

문자열 이름으로 변수 값 설정 및 가져 오기

eval작동 하는 동안 일반적으로 프로그램 자체에 의미가있는 변수 이름을 사용하지 않는 것이 좋습니다.

대신 dict을 사용하는 것이 좋습니다.

관용적이지 않다

에서 http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (강조 광산)

파이썬은 PHP가 아니다

다른 언어에서는 다르게 사용하기 때문에 파이썬 관용구를 우회하려고하지 마십시오. 네임 스페이스는 이유 가 있기 때문에 파이썬으로되어 있으며 도구를 제공한다고해서 해당 도구 exec를 사용해야한다는 의미는 아닙니다.

위험 해요

에서 http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (강조 광산)

따라서 모든 지구본과 내장을 제거하더라도 eval은 안전하지 않습니다!

eval ()을 보호하려는 이러한 모든 시도 의 문제점 은 이들이 블랙리스트라는 것 입니다. 그들은 위험 할 수있는 것을 명시 적으로 제거합니다. 목록에 남은 항목이 하나만 있으면 시스템을 공격 할 수 있기 때문에 전투에서 패배 합니다. .

그렇다면 평가를 안전하게 할 수 있습니까? 말하기 어렵다. 이 시점에서 가장 좋은 추측은 이중 밑줄을 사용할 수 없으면 아무런 해를 입을 수 없으므로 이중 밑줄이있는 문자열을 제외하면 안전합니다. 아마도...

읽고 이해하기 어렵다

에서 http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (강조 광산) :

첫째, exec인간이 코드를 읽기 어렵게 만듭니다 . 무슨 일이 일어나고 있는지 파악하기 위해 코드를 읽을 필요가 없으며 코드 를 읽고 생성 할 문자열을 파악한 다음 가상 코드를 읽어야합니다. 따라서 팀에서 작업하거나 오픈 소스 소프트웨어를 게시하거나 StackOverflow와 같은 곳에서 도움을 요청하는 경우 다른 사람들이 도움을주기가 더 어려워집니다. 6 개월 후이 코드를 디버깅하거나 확장 할 가능성이 있다면 직접 작성하기가 더 어려워집니다.


"내 최선의 추측은 이중 밑줄을 사용할 수 없으면 아무런 해를 끼칠 수 없다는 것입니다."-이중 밑줄을 포함하는 문자열을 구성한 다음 해당 문자열을 평가할 수 있습니다.
Stanley Bak

코드 생성기 또는 작업 러너 또는 이와 유사한 것을 작성하지 않는 한 좋은 조언입니다.
Erik Aronesty

나는의 (a 설정 파일에서 상대 경로를 가져올 수있다 cfg.yaml) reldir : ../my/dir/ , 그리고 reldir = cfg[reldir]. 그러나이 파이썬 코드는 Windows와 Linux 모두에서 실행되므로 다른 운영 체제 경로 분배기에 맞게 조정해야합니다. 하나 \\ 또는 /. 그래서 나는 reldir : os.path.join('..','my','dir')구성 파일에서 사용 합니다. 그러나 이것은 reldir이 리터럴 문자열 일뿐 이며 평가되지 않으므로에서 파일을 열 수 없습니다 reldir. 당신은 제안이 있습니까?
마리. 피.

9

다음 IDLE 세션과 같이 exec를 사용하여 코드 실행을 수행합니다.

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

4

1
일반적인 파이썬에서는 작동하지 않습니다. 파이썬 3에서 이상하지에서
토마스 Ahle

6

다른 사람들이 언급했듯이 "exec"..

그러나 코드에 변수가 포함 된 경우 "글로벌"을 사용하여 변수에 액세스 할 수 있으며 컴파일러가 다음 오류를 발생시키지 않도록 할 수 있습니다.

NameError : 이름 'p_variable'이 정의되지 않았습니다

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


4

그것의 가치 '가 언급 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 () 함수 를 사용하는 것입니다. 또 다른 해결책은 해당 문자열을 임시 파이썬 파일에 쓰고 실행하는 것입니다.


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.