[Python] 문자열을 코드로 (eval, exec 사용법)

반응형

python logo

 

파이썬을 사용하다 보면, 변수에 값을 동적으로 할당하고 싶을 때가 있습니다. 쉽게 말해, 파이썬의 문자열을 변수처럼 사용할 수 있다면, 자유롭게 값을 할당하고 다룰 수 있는 경우들이 있습니다. 이런 경우에 사용하는 것이 eval() 함수와 exec() 함수입니다. 이는 파이썬의 내장 함수로 따로 library 없이 사용할 수 있습니다.

 

Contents

     

    eval() 함수 : '수식' 연산

    기본적으로 문자열로 된 수식을 Input으로 받아 그 결과를 return 하는 함수입니다.

    eval('수식',globals=None, locals=None)

     

    ① '수식' : 여기에 문자열 형태로 표현식[ ex) 1+1 ]을 입력받습니다. (필요 값)

    ② globals : 선택적으로 쓰며, 사용하는 경우 변수: 값 형태의 딕셔너리를 사용합니다.

    ③ locals : 선택적으로 쓰며, 모든 매핑 객체를 사용할 수 있습니다.

     


     

    기초 사용법

    eval('수식') # 수식의 결과를 리턴

    '수식' 부분에 숫자의 연산을 넣을 수 도 있지만, 변수를 사용할 수 있고, 파이썬의 내장 함수들을 사용할 수 도 있으며, 필요하다면 라이브러리를 import 하여 사용할 수 도 있습니다.

     

    기초 예제 3가지

     

    ① 기초적인 숫자 연산

    eval('10+5') # 10 + 5 의 결과 리턴

    eval 함수 내에 문자열로 숫자의 연산을 작성하였습니다.

     

    * 출력

    eval 숫자 연산

     

    ② 변수와 내장 함수를 사용한 연산

    a=10  # 변수 설정
    eval('list(range(a))')

    a라는 변수에 10을 할당합니다. 그리고 eval 내부에서 list() 함수와 range() 함수 그리고, 변수 a를 같이 사용하여 0~9까지의 수를 리스트로 만들어 리턴합니다.

     

    * 출력

    eval 변수와 내장함수 사용

     

    ③ 라이브러리 import 하여 사용

    ## 일반적인 python 코드
    import random
    random.randint(0,10)
    
    eval('random.randint(0,10)')
    
    ## eval을 이용한 라이브러리 import와 코드
    eval("__import__('random').randint(0,10)")

    random 라이브러리를 import 하고 random.randint(0,10)을 사용하여 0 이상 10 이하의 랜덤 한 정수를 리턴하였습니다.

    외부에서 library를 import 하고 eval 함수 내에서 사용이 가능합니다. 또한, eval함수 내에서 라이브러리를 import 하여 사용할 수 도 있습니다. 

     

    하지만, 이때 eval 내부에서는 __import__('라이브러리') 형식으로 import 해야 하며, eval 함수 밖에서 해당 라이브러리를 사용할 수 없습니다.

     

    * 출력

    eval 함수와 random 라이브러리

     


     

    exex() 함수 : '코드' 실행

    기본적으로 문자열로 된 코드를 Input으로 받아 그 코드를 실행만 시키고, 아무것도 return하지 않습니다.

     

    eval과 차이점

    eval은 인자로 받은 수식의 결과를 리턴 하지만, exec는 값을 리턴하지 않습니다.

    즉, exec는 인자로 받은 문자열을 실행시키는데 목적이 있고, eval함수는 인자로 받은 문자열의 실행시킨 결과를 얻는데 목적이 있습니다.

    exec('코드', globals=None, locals=None)

     

    ① '코드' : 여기에 한 줄의 코드[ ex) x = 1+2]를 입력받습니다. (필요 값)

    ② globals : 선택적으로 쓰며, 사용하는 경우 변수: 값 형태의 딕셔너리를 사용합니다.

    ③ locals : 선택적으로 쓰며, 모든 매핑 객체를 사용할 수 있습니다.

     


     

    기초 사용법

    exec('코드') # 코드를 수행하며, exec함수는 아무것도 리턴하지 않음

    exec함수 내부에서

     

    예제 3가지

     

    ① exec로 변수 생성

    a=10
    exec("b = a + 20")
    b

    exec함수 밖에서 a라는 변수에 10을 넣고, exec에서 "b = a + 20"를 실행하였습니다.

    exec함수 외부에서 할당한 변수 a를 사용할 수 있고, b는 30이 됩니다.

     

    * 출력

     

    ② 라이브러리 사용하기

    import numpy as np
    
    exec("arr = np.array(range(10))")
    arr

    numpy 라이브러리의 np.array() 함수와 range(10)을 이용해 0부터 9까지 numpy array를 만들어봅니다.

    exec 함수 밖에서 선언한 라이브러리도 내부에서 사용 가능합니다.

     

    * 출력

     

    ③ eval, exec 같이 사용하기

    for i in range(1,4):
        exec(f"var_{i} = list(range(i))")
    
    for i in range(1,4):
        print(f'var_{i} :',eval(f'var_{i}'))

    위에서 배운 eval과 exec를 사용하면 문자열 변수에 값을 동적으로 할당할 수 있습니다.

    할당 : for문을 반복하며 1부터 3까지 var_1, var_2, var_3을 만들어 각각 list(range(1)), list(range(2)), list(range(3))을 동적으로 할당합니다.

    출력 : 마찬가지로 for문을 반복하며 1부터 3까지 var_1, var_2, var_3을 출력(print)해봅니다. 

     

    * 문자열에 변수의 값을 쓰는 f스트링을 사용하였습니다. 사용방법은 f"{변수}"로 하면, 변수의 값이 문자열로 써집니다.

     

    * 출력

     

    마치며

    eval함수와 exec함수는 내부에서 문자열을 실행시키기 때문에 편리합니다. 특히, eval과 exec를 같이 사용하면 여러 변수들에 동적으로 값을 할당하여 사용할 수 있습니다.

     하지만, 강력한 만큼 Command Injection 공격에 취약하기도 합니다. Command Injection 공격이란 특정 명령을 스크립트 내부에 삽입하여 실행시키는 공격입니다. 사용자의 값이 적절한지 검증 없이 시스템 조작이 가능하기 때문에 주의할 필요가 있습니다.

     

    위의 예제 코드 깃허브를 공유드립니다.

    https://github.com/netsus/python_practice/blob/master/python_practice_5_eval_exec.ipynb

     

    GitHub - netsus/python_practice: basic python course

    basic python course. Contribute to netsus/python_practice development by creating an account on GitHub.

    github.com

     

    Reference)
    python logo: https://commons.wikimedia.org/wiki/File:Python_logo_and_wordmark.svg
    반응형

    댓글

    Designed by JB FACTORY