ㅍㅍㅋㄷ

python eval 과 literal_eval 의 차이 본문

Programming/Python

python eval 과 literal_eval 의 차이

클쏭 2019. 1. 22. 18:29

python - literal_eval 은 정말 안전한 eval 인 것인가.


지난 포스팅에서 eval() 에 대해 알아 보았는데(eval()함수 사용을 조심해야 하는 이유), 

마지막에 literal_eval 에 대해 잠깐 언급하였다. 

이번 포스팅에서는 literal_eval 이 어떤 놈인지, eval 과는 어떤 차이가 있는지 알아보려 한다. 


literal_eval은 eval 과는 다르게 built-in 함수는 아니며, 

AST(Abstract Syntax Trees) module 에서 제공하는 함수 중 하나이다. 

AST 모듈은 문법을 구조화 시켜주는 모듈 정도로 이해하고 넘어가자. 


literal_eval에 대한 Python docs 를 보면 아래와 같이 설명되어 있다.


ast.literal_eval(node_or_string) 


 Safely evaluate an expression node or a string containing a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None.

This can be used for safely evaluating strings containing Python values from untrusted sources without the need to parse the values oneself. It is not capable of evaluating arbitrarily complex expressions, for example involving operators or indexing.


 literal_eval 은 말그대로 literal(=문자 그대로) evaluate 를 실행하는 함수이다. 즉, python 에서 제공하는 기본 type 정도만 변환해주는 용도로 사용 가능하다.


import ast


str_dict = "{'a': 3, 'b': 5}"

print type(str_dict)           # <type 'str'>


convert_dict = ast.literal_eval(str_dict)


print type(convert_dict)   # <type 'dict'>

print convert_dict['a']      #  3

print convert_dict['b']      #  5

 

위와 같이, dictionary 형태로 저장된 string 값을 str_dict 에 저장 후, 이를 literal_eval 을 통해 실제 dictionary 로 가공한 것을 볼 수 있다.

그렇다면, eval 에서의 경우와 같이 함수나 객체를 literal_eval 을 통해 실행이 가능할까?


import ast


str = '__import__("os").system("ls /")'


print type(str)       # <type 'str'>


eval(str)               # 흠좀무

'''

Applications Volumes home tmp

Developer bin installer.failurerequests usr

Library cores macOS Install Data var

Network data net

System dev private

Users etc sbin

'''



ast.literal_eval(str)

'''

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ast.py", line 80, in literal_eval

    return _convert(node_or_string)

  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ast.py", line 79, in _convert

    raise ValueError('malformed string')

ValueError: malformed string

'''


literal_eval 의 경우는 ValueError 를 발생시킴을 알 수 있다.

간단한 수학 연산은 먹힐까.


ast.literal_eval("10 * 2")

'''

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ast.py", line 80, in literal_eval

    return _convert(node_or_string)

  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ast.py", line 79, in _convert

    raise ValueError('malformed string')

ValueError: malformed string

'''

 

얄짤없다.

literal_eval은 python 의 기본 자료형 정도만 evaluate 가 가능하도록 지원한다. eval 과 비교해 훨씬 엄격하기 때문에 결과적으로 안전을 보장한다고 설명한 것이다. 

결과적으로 eval 대비 안전하겠지만,  그 사용 용도가 eval 대비 훨씬 제한적일 수 밖에 없다는 것을 기억해 두자.


이쯤 되면, literal_eval 이 왜 AST 모듈에 존재하는지도 대충 이해가 될 것이다.

위에서 언급한것 처럼 AST 모듈은 Syntax 를 구조화하는 모듈이기 때문에, literal_eval 의 용도인 string을 자료형으로 구조화 시키는 것과 그 목적을 같이 한 것으로 이해해도 될 것 같다.





[참고]

  • https://docs.python.org/3/library/ast.html#ast.literal_eval
  • https://stackoverflow.com/questions/15197673/using-pythons-eval-vs-ast-literal-eval



Comments