[Python] eval() 메소드: 동적으로 문자열 표현식을 평가하여 실행 (Evaluate expressions dynamically)
Python 분석과 프로그래밍/Python 설치 및 기본 사용법 2023. 5. 21. 21:50이번 포스티에서는 Python의 내장 함수인 eval() 함수에 대해서 소개하겠습니다.
(1) Python의 eval() 함수 구문 이해 및 문자열 표현식 인풋을 eval() 함수에 사용하기
(2) eval() 함수의 잘못된 사용 예시 (SyntaxError)
(3) compiled-code-based 인풋을 eval() 함수에 사용하기
(1) Python의 eval() 함수 구문 이해 및 문자열 표현식 인풋을 eval() 함수에 사용하기
Python 의 내장함수(built-in function)인 eval() 함수는 임의의 문자열 기반(string-based) 또는 컴파일된 코드 기반 (compiled-code-based) 인풋의 표현식(expressions)을 평가(evaluate)해서 실행해줍니다.
문자열 기반의 표현식을 eval() 함수가 처리하는 순서는 아래와 같습니다.
(1-a) 문자열 기반 표현식을 파싱한다. (Parse a string-based expression)
(1-b) 문자열을 파싱한 결과를 바이트코드로 컴파일한다. (Compile it to bytecode)
(1-c) 파이썬 표현식으로 평가한다. (Evaluate it as a Python expression)
(1-d) 평가한 결과를 하나의 값으로 반환한다. (Return the result of the evaluation)
아래 예시는 문자열 기반 표현식 (string-based expressions) 으로 수학 계산식(math expressions)을 인풋으로 해서 eval() 메소드를 사용해 동적으로 평가하여 실행한 것입니다.
## You can use the built-in Python eval()
## to dynamically evaluate expressions
## from a string-based or compiled-code-based input.
##-- eval() for a string-based input
##-- Math expressions
eval("2 + 6")
# 8
eval("10**2")
# 100
eval("sum([1, 2, 3, 4, 5])")
# 15
import math
eval("math.pi * pow(5, 2)")
# 78.53981633974483
eval() 함수는 문자열 표현식에서 아래 예의 x 와 같은 글로벌 변수에 접근해서 표현식을 평가하고 실행할 수 있습니다.
## eval() has access to global names like x
x = 10
eval("x * 5")
# 50
eval() 함수는 문자열의 블리언 표현식 (Boolean expressions)에 대해서도 평가하여 실행할 수 있습니다.
아래의 예에서는 순서대로 블리언 표현식 (Boolean expressions)의
(a) 비교 연산자 (value comparison operstors: <, >, <=, >=, ==, !=)),
(b) 논리 연산자 (logical operators: and, or, not),
(c) 소속 여부 확인 연산자 (membership test operators: in, not in),
(d) 동일 여부 확인 연산자 (identity operators: is, is not)
을 사용한 문자열 기반 인풋을 eval() 메소드를 통해 평가하고 실행해 보았습니다.
## -- eval() for Boolean expressions
x = 10
## (a) value comparison operators: <, >, <=, >=, ==, !=
eval("x > 5")
# True
## (b) logical operstors: and, or, not
eval("x > 5 and x < 9")
# False
## (c) membership test operators: in, not in
eval("x in {1, 5, 10}")
# True
## (d) identity operators: is, is not
eval("x is 10")
# True
그러면, 그냥 Python 표현식을 쓰면 되지, 왜 굳이 문자열 기반의 표현식을 eval() 함수에 인풋으로 넣어서 쓸까 궁금할 것입니다. 아래의 조건 표현식을 가지는 사용자 정의 함수를 예로 들자면, 사용자 정의함수 myfunc() 를 사용할 때처럼 동적으로 문자열 기반의 조건절 표현식을 바꾸어가면서 쓸 수 있어서 강력하고 편리합니다.
## suppose you need to implement a conditional statement,
## but you want to change the condition on the fly, dynamically.
def myfunc(a, b, condition):
if eval(condition):
return a + b
return a - b
myfunc(5, 10, "a > b")
# -5
myfunc(5, 10, "a <= b")
# 15
myfunc(5, 10, "a is b")
# -5
(2) eval() 함수의 잘못된 사용 예시 (SyntaxError)
(2-1) 만약 eval() 함수의 인풋으로 표현식(expressions) 이 아니라, if, while 또는 for 와 같은 키워드를 사용해서 만든 코드 블락으로 이루어진 명령문(statement)을 사용한다면 "SyntaxError: invalid syntax" 에러가 발생합니다.
## if you pass a compound statement to eval(),
## then you'll get a SyntaxError.
x = 10
eval("if x>5: print(x)")
# File "<string>", line 1
# if x>5: print(x)
# ^
# SyntaxError: invalid syntax
(2-2) eval() 함수에 할당 연산(assignment operations: =) 을 사용하면 "SyntaxError: invalid syntax" 에러가 발생합니다.
## Assignment operations aren't allowed with eval().
eval("x = 10")
# File "<string>", line 1
# x = 10
# ^
# SyntaxError: invalid syntax
(2-3) Python 구문의 규칙을 위배하면 "SyntaxError: unexpedted EOF while parsing" 에러가 발생합니다.
(아래 예에서는 "1 + 2 -" 에서 문자열 마지막에 - 부호가 잘못 들어갔음)
## If an expression violates Python syntax, then SyntaxError
eval("1 + 2 -")
# File "<string>", line 1
# 1 + 2 -
# ^
# SyntaxError: unexpected EOF while parsing
(3) compiled-code-based 인풋을 eval() 함수에 사용하기
eval() 함수의 인풋으로 위의 문자열 기반 객체 대신 compiled-code-based 객체를 사용할 수도 있습니다. compiled-code-based 객체를 eval() 함수의 인풋으로 사용하면 아래의 두 단계를 거칩니다.
(3-a) 컴파일된 코드를 평가한다. (Evaluate the compiled code)
(3-b) 평가 결과를 반환한다. (Return the result of the evaluation)
위의 (1)번에서 문자열 기반의 표현식을 eval() 함수의 인풋으로 사용했을 때 대비 compiled-code 객체를 eval() 함수의 인풋으로 사용할 경우 파싱하고 컴파일 하는 단계가 없고, 바로 컴파일된 코드를 평가하고 반환하는 단계로 넘어가므로 똑같은 표현식을 여러번 평가해야 하는 경우에 속도 향상을 기대할 수 있습니다.
Python의 eval() 함수에 compiled code 객체를 인풋으로 사용하려면,
compiled_code_object = compile(source, filename, mode) 의 구문을 사용해서 컴파일 해주면 됩니다.
- source 에는 문자열 표현식(string-based expression)을 넣어줍니다.
- filename 에는 문자열 기반 표현식을 사용할 경우 "<string>" 을 써줍니다.
- mode 에는 컴파일된 코드를 eval() 함수로 처리하길 원할 경우 "eval" 을 써줍니다.
##-- eval() for compiled-code-based input
compiled_code = compile("(2 + 3) * 10", "<string>", "eval")
eval(compiled_code)
# 50
[ Reference ]
* Real Python site: "Python eval(): Evaluate Expressions Dynamically
: https://realpython.com/python-eval-function/
이번 포스팅이 많은 도움이 되었기를 바랍니다 .
행복한 데이터 과학자 되세요! :-)
'Python 분석과 프로그래밍 > Python 설치 및 기본 사용법' 카테고리의 다른 글
[Python] List Comprehension 에 대한 이해 (0) | 2023.05.29 |
---|---|
[Python] 유닉스 스타일 경로명 패턴 확장 glob, 파일명 패턴 매칭 fnmatch (0) | 2023.04.02 |
[Python] 여러개의 Python 패키지, 모듈을 한꺼번에 설치하는 방법 (0) | 2023.03.12 |
[Jupyter Notebook] 주피터 노트북의 Cell 결과 모두 지우고, 새로 시작하기 (0) | 2023.03.05 |
[Python] 웹사이트에서 압축파일 다운받아 압축해제 후 데이터셋 합치기 (0) | 2021.10.07 |