파이썬의 eval ()은 무엇을합니까?


306

파이썬에서 읽고있는 책에서 코드를 계속 사용합니다. eval(input('blah'))

설명서를 읽고 이해했지만 여전히 input()기능이 어떻게 바뀌는 지 알 수 없습니다 .

무엇을합니까? 누군가 설명 할 수 있습니까?


4
평가 함수는 파이썬 코드로 전달 된 문자열 (인수)을 실행하고 해석하려고합니다. x = 1 print (eval ( 'x + 1')) 위 코드의 출력은 2가 될 것입니다. 이러한 접근 방식의 단점은 사용자가 코드 작성에 독립적이어서 혼란스러운 조건을 초래할 수 있다는 것입니다. eval 함수에서 전역 및 로컬 매개 변수를 전달하여 많은 변수 및 메소드에 액세스
ATIF IBAD KHAN

답변:


276

eval 함수를 사용하면 Python 프로그램이 자체적으로 Python 코드를 실행할 수 있습니다.

평가 예 (대화식 쉘) :

>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1

25
하하, 그것은 사소한 예이지만, 사용자가 임의의 명령을 입력하고 파이썬이 실행하도록 할 수 있습니다. 따라서 사용자는 명령 문자열에 사용자 유형을 입력하고 파이썬으로 코드로 실행할 수 있습니다. 예를 들어, eval ( "__ import __ ( 'os'). remove ( 'file')")입니다.
BYS2

60
당신이 그것을 찾을 때까지 쓸모없는 것 같습니다. codepad.org와 같은 사이트에서 테스트 환경에서 스크립트를 실행할 수 있도록 사용됩니다. eval()동적 코드를 실행하는 데 사용될 수도 있지만 사용하기 전에 보안 및 성능 위험을 완전히 인식해야합니다.
George Cummins

6
@GeorgeCummins, codepad.org는을 사용하지 않으며 eval그것으로하는 일도 할 수 없습니다 eval.
Mike Graham

16
@GeorgeCummins : codepag.org는 샌드 박스에서 모든 것을 실행합니다. 가상 머신에서 ptrace 검사가 포함 된 chroot jail은 악성 코드가 나쁜 일을하지 않도록합니다. 단순한 평가보다 훨씬 더 복잡합니다. 또한 eval은 Python에 따라 다릅니다. 코드 패드는 여러 언어를 지원합니다.
FogleBird

4
@GeorgeCummins, 코드 패드는 임의의 프로그램을 안전하게 실행하기 위해 매우 복잡한 시스템을 실행합니다. eval안전하지 않은 것 외에는 단일 표현식 만 평가할 수 있기 때문에 코드 패드와 같은 전체 프로그램을 실행할 수 없습니다.
Mike Graham

165

eval()문자열을 코드로 해석합니다. 많은 사람들이 이것을 사용하는 것에 대해 경고 한 이유는 사용자가 이것을 컴퓨터에서 코드를 실행하는 옵션으로 사용할 수 있기 때문입니다. 당신이있는 경우 eval(input())os수입, 한 사람에 입력 할 수 있습니다 input() os.system('rm -R *')홈 디렉토리에있는 모든 파일을 삭제할 것이다. (유닉스 시스템이 있다고 가정). 사용 eval()은 보안상의 허점입니다. 문자열을 다른 형식으로 변환해야하는 경우와 같이 그렇게하는 것을 사용하십시오 int().


14
evalwith를 사용 하는 input()것은 보안상의 허점임을 의미 합니다. input()평가 명세서에 넣지 마십시오 . 괜찮을 것입니다.
Rohmer

19
@Rohmer, 안전하지 않은 데이터는 콘솔 입력뿐만 아니라 웹 요청, 양식 입력 필드, 파일 읽기 등 모든 곳에서 나올 수 있습니다. 파일을 직접 작성하더라도 원래 신뢰할 수없는 소스에서 온 입력을 포함 할 수 있습니다. 그래서 eval많은 경우에 보안 문제입니다.
sanderd17

3
때문에 input일반적으로 콘솔에서 데이터를 취 사용자는 프로그램을 종료하고 입력 할 수 있습니다 rm -R *... 어쨌든
CZ

63

좋은 여기에 대한 답변,하지만 아무도 많이 사용 설명 eval()의 맥락에서 globalslocals즉 kwargs로, eval(expression, globals=None, locals=None)(대한 문서를 참조 eval 여기를 ).

이들은 기능을 통해 사용 가능한 기능을 제한하는 데 사용될 수 있습니다 eval. 예를 들어 새로운 파이썬 인터프리터를로드하면 locals()and 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

확인. 그래서 우리는 우리가 노출시키고 자하는 하나의 함수와 우리가 노출하고 싶지 않은 하나의 (훨씬 더 복잡한) 방법의 예를 볼 수 있습니다. 모든 것을 차단합시다.

>>>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으로 큰 가치로 안전하게 사용할 수 있다고 생각 합니다.

NB

이것들에 대한 다른 멋진 점은 kwargs코드에 속기를 사용할 수 있다는 것입니다. 가져온 텍스트를 실행하기 위해 eval을 파이프 라인의 일부로 사용한다고 가정 해 봅시다. 텍스트는 정확한 코드를 가질 필요가 없으며 일부 템플릿 파일 형식을 따를 수 있으며 여전히 원하는 것을 실행할 수 있습니다. 예를 들면 다음과 같습니다.

>>>from os import cpu_count
>>>eval('[1,cores]', {'__builtins__': None}, {'cores': cpu_count()})
[1, 8]

29

파이썬 2.X에서 input(...)와 같습니다 eval(raw_input(...)), 파이썬 3.x의에서 raw_input이름이 바뀌 었 input하는 I 의심 리드 당신의 혼란, (당신은 아마에 대한 문서보고 있었다 input파이썬 2.X에서). 또한 eval(input(...))Python 3.x에서는 잘 작동하지만 TypeErrorPython 2에서는 증가합니다 .

이 경우 표현식 eval에서 리턴 input되고 해석 되는 문자열을 강제하는 데 사용됩니다 . 일반적으로 이것은 나쁜 습관으로 간주됩니다.


또는 2.x에서 한 input일을 의미 하는 Python 3.x 책 raw_input입니다.
dan04

1
네, 첫 답변을 쓴 후에 나에게 이런 일이 생겼습니다.
zeekay

6

행을 읽고 해석하는 잘못된 예일 수 있습니다.

시도 eval(input())하고 입력하십시오 "1+1"-인쇄해야합니다 2. 평가 식을 평가합니다.


따옴표 사이에 왜 입력해야합니까? 입력이 문자열을 가져 와서 코드를 실행하지 않고 eval로 전달하므로 단순히 1 + 1을 입력하면 괜찮을 것입니다 ... ¿?
JC Rocamonde

문제는 P2.x와 3.x를 혼합한다는 것입니다. 파이썬 2에서는 코드가 작동하지만 두 번 평가하는 것은 의미가 없습니다. 파이썬 3에서는 그렇지 않고 문자열을 반환합니다.
JC Rocamonde

6

eval()전달 된 문자열을 Python 표현식으로 평가하고 결과를 리턴합니다. 예를 들어, eval("1 + 1")표현식을 해석하고 실행 "1 + 1"하고 결과를 리턴합니다 (2).

혼동 될 수있는 한 가지 이유는 인용 한 코드에 간접적 인 수준이 관련되어 있기 때문입니다. 내부 함수 호출 (입력)이 먼저 실행되므로 "blah"프롬프트가 표시됩니다. "1 + 1"(명확성을 위해 추가 된 인용 부호, 프로그램을 실행할 때 입력하지 않음)로 응답한다고 가정하고 입력 함수는 해당 문자열을 반환 한 다음 문자열을 해석하는 외부 함수 (eval)로 전달합니다. 결과를 반환합니다 (2).

eval에 대한 자세한 내용은 여기를 참조 하십시오 .


6

eval()이름에서 알 수 있듯이 전달 된 인수를 평가합니다.

raw_input()이제 input()파이썬 3.x의 버전에서. 따라서 가장 일반적으로 사용되는 예 는 2.x 버전의 Python에서 eval()제공하는 기능을 제공하는 것입니다 input(). raw_input은 사용자가 입력 한 데이터를 문자열로 반환했지만 입력은 입력 한 데이터의 값을 평가하여 반환했습니다.

eval(input("bla bla"))따라서 input()2.x 의 기능 , 즉 사용자가 입력 한 데이터를 평가 하는 기능을 복제합니다 .

간단히 말해서 : eval()전달 된 인수를 평가하여 eval('1 + 1')2를 반환 했습니다 .


6

유용한 응용 프로그램 중 하나는 eval()문자열에서 파이썬 표현식을 평가하는 것입니다. 예를 들어 사전의 파일 문자열 표현에서로드 :

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'}

7
이것은 무엇을 요구하는 질문에 어떻게 대답 eval합니까?
jkd

4

나는이 질문에 대답하기 늦었지만 아무도 그 질문에 대한 명확한 대답을하지 않는 것 같습니다.

사용자가 숫자 값을 입력 input()하면 문자열이 반환됩니다.

>>> input('Enter a number: ')
Enter a number: 3
>>> '3'
>>> input('Enter a number: ')
Enter a number: 1+1
'1+1'

따라서 eval()문자열 인 반환 값 (또는 표현식)을 평가하고 정수 / 부동 소수점을 반환합니다.

>>> 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

3

평가 문자열을 간단한 리터럴로 제한하려는 경우 다른 옵션을 사용하는 것 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}

로부터 문서 :

파이썬 리터럴 또는 컨테이너 디스플레이를 포함하는 표현식 노드 또는 문자열을 안전하게 평가하십시오. 제공된 문자열 또는 노드는 문자열, 바이트, 숫자, 튜플, 목록, dicts, set, booleans 및 None과 같은 Python 리터럴 구조 로만 구성 될 있습니다.

값을 직접 구문 분석 할 필요없이 신뢰할 수없는 소스의 Python 값을 포함하는 문자열을 안전하게 평가하는 데 사용할 수 있습니다. 그것은 것입니다 하지 운영자 또는 색인을 포함하는, 예를 들어, 임의의 복잡한 식을 평가할 수.

메일 링리스트 에서 왜 그렇게 제한되어 있는지에 관해서 :

리터럴로 연산자 표현식을 허용하는 것이 가능하지만 현재 구현보다 훨씬 복잡합니다. 간단한 구현은 안전하지 않습니다. 노력없이 기본적으로 무제한 CPU 및 메모리 사용을 유도 할 수 있습니다 ( "9 ** 9 ** 9"또는 "[없음] * 9 ** 9"시도).

유용성에 관해서는,이 함수는 리터럴 값과 컨테이너를 repr ()에 의해 문자열로 "판독"하는데 유용합니다. 예를 들어 JSON과 비슷하지만 더 강력한 형식으로 직렬화에 사용할 수 있습니다.


1
ast.literal_eval귀하의 '1+1'예 와 달리 연산자를 지원하지 않습니다 . 그럼에도 불구하고 목록, 숫자, 문자열 등을 지원하므로 일반적인 eval사용 사례에 대한 좋은 대안입니다 .
benjimin

@ benjimin 아 맞아-그것은 1 + 1을 받아들이는 기발한 일입니다! stackoverflow.com/questions/40584417/…
Brian Burns
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.