Python Language
`exec`와`eval`을 이용한 동적 코드 실행
수색…
통사론
- eval (expression [, globals = None [, locals = None]])
- exec (객체)
- exec (객체, 전역)
- exec (객체, 전역, 지역)
매개 변수
논의 | 세부 |
---|---|
expression | 표현식 코드를 문자열 또는 code 객체 |
object | 명령문 코드를 문자열 또는 code 객체 |
globals | 전역 변수에 사용할 사전입니다. 지역을 지정하지 않으면 지역 주민에게도 사용됩니다. 생략하면 호출 영역의 globals() 가 사용됩니다. |
locals | 로컬 변수에 사용되는 매핑 객체입니다. 생략하면 globals 에 대해 전달 된 값이 대신 사용됩니다. 둘 다 생략되면 호출 범위의 globals() 및 locals() 가 globals 및 locals 각각 사용됩니다. |
비고
exec
에서 globals
가 locals
인 경우 (즉, 동일한 객체를 참조하는 경우) 코드는 모듈 수준에있는 것처럼 실행됩니다. globals
와 locals
globals
가 다른 객체 인 경우 코드는 클래스 본문 에있는 것처럼 실행됩니다.
globals
객체가 전달되었지만 __builtins__
키가 지정되어 있지 않으면 Python 기본 제공 함수와 이름이 자동으로 전역 범위에 추가됩니다. 같은 함수의 가용성 억제하기 위해 print
또는 isinstance
실행 된 범위를하자 globals
키가 __builtins__
중시하지 매핑 None
. 그러나 이것은 보안 기능이 아닙니다.
파이썬 2 특정 구문을 사용하면 안됩니다. 파이썬 3 구문은 파이썬 2에서 작동합니다. 따라서 다음 형식은 더 이상 사용되지 않습니다 : <s>
-
exec object
-
exec object in globals
-
exec object in globals, locals
exec로 문장 평가하기
>>> code = """for i in range(5):\n print('Hello world!')"""
>>> exec(code)
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
eval로 표현식 평가하기
>>> expression = '5 + 3 * a'
>>> a = 5
>>> result = eval(expression)
>>> result
20
표현식을 여러 번 평가하기 위해 프리 컴파일
compile
내장 함수는 코드 오브젝트에 표현식을 프리 D 파일하는 데 사용할 수 있습니다. 이 코드 객체는 eval에 전달 될 수 있습니다. 이렇게하면 평가 된 코드가 반복적으로 실행됩니다. compile
세 번째 매개 변수는 'eval'
문자열이어야합니다.
>>> code = compile('a * b + c', '<string>', 'eval')
>>> code
<code object <module> at 0x7f0e51a58830, file "<string>", line 1>
>>> a, b, c = 1, 2, 3
>>> eval(code)
5
맞춤 전역을 사용하여 eval로 표현식 평가하기
>>> variables = {'a': 6, 'b': 7}
>>> eval('a * b', globals=variables)
42
더하기,이 코드는 실수로 외부에서 정의 된 이름을 참조 할 수 없습니다.
>>> eval('variables')
{'a': 6, 'b': 7}
>>> eval('variables', globals=variables)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'variables' is not defined
defaultdict
사용하면 예를 들어 정의되지 않은 변수를 0으로 설정할 수 있습니다.
>>> from collections import defaultdict
>>> variables = defaultdict(int, {'a': 42})
>>> eval('a * c', globals=variables) # note that 'c' is not explicitly defined
0
ast.literal_eval을 사용하여 파이썬 리터럴을 포함하는 문자열 평가
문자열, 부동 소수점 등의 파이썬 리터럴을 포함하는 문자열이있는 경우 ast.literal_eval
을 사용하여 eval
대신 값을 평가할 수 있습니다. 이것은 특정 구문만을 허용하는 추가 기능을 가지고 있습니다.
>>> import ast
>>> code = """(1, 2, {'foo': 'bar'})"""
>>> object = ast.literal_eval(code)
>>> object
(1, 2, {'foo': 'bar'})
>>> type(object)
<class 'tuple'>
그러나이 방법은 신뢰할 수없는 사용자가 제공 한 코드를 실행하는 데 안전하지 않으며주의 깊게 작성된 입력을 사용하여 통역사를 다운시키는 것도 쉽지 않습니다.
>>> import ast
>>> ast.literal_eval('()' * 1000000)
[5] 21358 segmentation fault (core dumped) python3
여기서 입력의 문자열 ()
CPython의 파서에서 충돌이 발생 백만 번 반복은. CPython 개발자는 파서의 버그를 보안 문제로 간주하지 않습니다.
exec, eval 또는 ast.literal_eval을 사용하여 신뢰할 수없는 사용자가 제공 한 코드 실행
신뢰할 수없는 사용자의 코드를 eval
또는 exec
를 사용하여 안전하게 실행할 수 없습니다. 심지어 ast.literal_eval
은 파서에서 충돌하는 경향이 있습니다. 때로는 악의적 인 코드 실행을 막는 것이 가능하지만 파서 또는 토크 나이저에서 명백한 충돌 가능성을 배제하지 않습니다.
신뢰할 수없는 사용자가 코드를 평가하려면 타사 모듈로 전환하거나 Python으로 자체 파서와 자체 가상 머신을 작성해야합니다.