문자를 그대로 실행하고 싶을 때
pandas.DataFrame으로 데이터를 읽어왔더니 값에 리스트가 통째로 들어있거나, 딕셔너리가 들어있는 경우가 있던 적이 있다. 해당 값은 진짜 리스트, 진짜 딕셔너리가 아닌 그런 척 하는 문자열일 뿐이었다.
이런 경우에는 어떻게 값을 처리해주어야 할지 난감할 수 있다. 이 때 사용할 수 있는 ast 모듈과 eval 함수를 소개하고 그 차이를 비교해보자.
ast.literal_eval
공식 문서 https://docs.python.org/3/library/ast.html#ast.literal_eval
ast 모듈은 문법을 구조화 시켜주는 모듈이다. 그 중 literal_eval 함수는 이름처럼 문자(literal) 그대로 평가(evaluate)하는 것이다. 즉, string을 자료형으로 구조화한다. 이 때 python의 기본 자료형 정도만 evaluate가 가능하도록 지원한다.
import ast
str_dict = "{'id': 1, 'name': '홍길동'}"
print(type(str_dict)) # <type 'str'>
convert_dict = ast.literal_eval(str_dict)
print(type(convert_dict)) # <type 'dict'>
print(convert_dict['name']) # '홍길동'
import ast
str_list = "['홍길동', '김철수', '이영희']"
print(type(str_list)) # <type 'str'>
convert_list = ast.literal_eval(str_list)
print(type(convert_list)) # <type 'list'>
print(convert_list[0]) # '홍길동'
문자열이었던 변수를 ast.literal_eval을 사용하여 자료형을 dictionary, list로 변환하였다. 변환된 변수는 key로 값을 참조하는 딕셔너리나 index로 값을 참조하는 리스트의 성질을 정상적으로 사용할 수 있다.
eval
공식 문서 https://docs.python.org/3/library/functions.html?highlight=eval#eval
빌트인 함수 중 하나인 eval 함수는 위에서 설명한 ast.literal_eval과 비슷하지만 꽤 다르다.
함수는 string 값을 전달하면 해당 값을 그대로 실행하여 결과를 출력해주는 역할을 하는데, 얼핏 들으면 ast.literal_eval과 유사해보인다.
하지만 eval 함수는 매우 강력하기 때문에 오히려 사용을 자제하도록 권고하는 양날의 검과 같은 기능을 가지고 있다.
ast.literal_eval과 유사한 기능
str_dict = "{'id': 1, 'name': '홍길동'}"
print(type(str_dict)) # <type 'str'>
convert_dict = eval(str_dict)
print(type(convert_dict)) # <type 'dict'>
print(convert_dict['name']) # '홍길동'
문자열이었던 변수를 dictionary로 변환하였다. 변환된 변수는 딕셔너리 성질을 정상적으로 사용할 수 있다.
강력한 기능
eval("(5 * 10) / 2") # 25
eval("max([1, 2, 3, 4])") # 4
eval("input('입력: ')") # 입력: (입력 후 엔터 시 출력)
문자열 안에 어떤 것이 있든 실제 터미널에서 실행하는 것 처럼 실행해버린다.
처음엔 신기하기도 하고, 잘 사용하면 굉장히 좋겠다는 생각을 했으나, 장점을 다 묻어버릴 주의해야 할 점이 있다.
주의
eval("__import__('os').system('ls /')") # 서버의 root 디렉토리의 정보가 그대로 노출!!
서버 정보를 알 수 있는 코드가 담긴 문자열을 eval에 입력하면 그대로 실행되어 정보를 노출한다.
이는 개발자라면 당연히 고려해야하는 보안 측면에서 굉장히 위험하다.
command injection flaws(명령 삽입 결점)을 그대로 노출할 수 있기때문에 자칫하면 대형 참사로 이어질 것이다.
또한 코드의 가독성이 떨어지고 디버깅이 어려워진다. eval을 사용하여 일부 로컬 환경에 의존하도록 구현할 경우 환경 의존성도 생길 수 있다.
ast.literal_eval VS eval
한마디로 정리하자면, eval은 되도록 사용하지 않는 방향을 권고한다.
물론 사용 용도가 eval에 대비해 ast.literal_eval이 훨씬 제한적이다.
하지만 eval과 비교해 훨씬 엄격한 ast.literal_eval을 사용하면 안전을 보장할 수 있다.
'Python' 카테고리의 다른 글
[python] DataFrame 결합 - pandas.merge (0) | 2023.07.31 |
---|---|
[python] DataFrame 결합 - pandas.concat (0) | 2023.07.28 |
[python] csv 모듈 사용하기 (0) | 2023.07.25 |
[python] APScheduler 사용하기 (1) | 2023.07.20 |
[python] pymysql VS sqlalchemy 소개 및 사용법 (0) | 2023.07.19 |