eval, exec 및 compile의 차이점은 무엇입니까?


428

파이썬 코드의 동적 평가를 살펴보고 eval()compile()함수와 exec명령문을 보았습니다 .

누군가 eval와 의 차이점을 설명해 주시겠습니까?exec , 방법의 다른 모드 compile()에 맞게?

답변:


517

짧은 대답 또는 TL; DR

기본적으로 동적으로 생성 된 단일 Python 표현식 eval평가 하는 exec데 사용되며 실행 하는 데 사용됩니다. 부작용에 대해서만 동적으로 생성 된 Python 코드 .

eval그리고 exec이 두 가지 차이점이 있습니다 :

  1. eval만 받아들이는 하나의 표현 , exec루프 : 파이썬 문이 코드 블록이 걸릴 수 try: except:, class및 기능 / 방법 def등 initions하고 있습니다.

    파이썬의 표현식은 변수 할당의 값으로 가질 수있는 것입니다.

    a_variable = (anything you can put within these parentheses is an expression)
  2. eval 주어진 표현식 의 값반환하는 반면 exec코드에서 반환 값을 무시하고 항상 반환합니다 None(파이썬 2에서는 명령문이며 표현식으로 사용할 수 없으므로 실제로 아무것도 반환하지 않습니다).

버전 exec1.0-2.7에서는 CPython exec이 함수 내부의 부작용에 사용 된 함수에 대해 다른 종류의 코드 오브젝트를 생성해야했기 때문에 명령문이었습니다 .

파이썬 3에서는 exec함수입니다. 사용되는 함수의 컴파일 된 바이트 코드에는 영향을 미치지 않습니다.


따라서 기본적으로 :

>>> a = 5
>>> eval('37 + a')   # it is an expression
42
>>> exec('37 + a')   # it is an expression statement; value is ignored (None is returned)
>>> exec('a = 47')   # modify a global variable as a side effect
>>> a
47
>>> eval('a = 47')  # you cannot evaluate a statement
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    a = 47
      ^
SyntaxError: invalid syntax

compile'exec'모드는 바이트 코드로 문의 수를 컴파일하는 암시 적으로 항상 반환 None에있는 반면, 'eval'모드 그것은 컴파일 바이트 코드로 표현이 반환 하는 식의 값.

>>> eval(compile('42', '<string>', 'exec'))  # code returns None
>>> eval(compile('42', '<string>', 'eval'))  # code returns 42
42
>>> exec(compile('42', '<string>', 'eval'))  # code returns 42,
>>>                                          # but ignored by exec

에서 'eval'합니다 (에 따라서 모드 eval문자열이 전달되면 기능)는이 compile소스 코드를 진술 또는 하나의 표현을 넘어 다른 것을 포함 된 경우 예외가 발생 :

>>> compile('for i in range(3): print(i)', '<string>', 'eval')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    for i in range(3): print(i)
      ^
SyntaxError: invalid syntax

실제로 "eval은 단일 표현식 만 허용 합니다 " 라는 문장 은 문자열 (Python 소스 코드 를 포함 )이 전달 될 때만 적용됩니다 eval. 그런 다음 compile(source, '<string>', 'eval')이를 사용하여 내부적으로 바이트 코드로 컴파일됩니다 .

경우 code(파이썬 포함 개체 바이트 코드가 )에 전달 exec하거나 eval, 그들은 동일하게 작동 사실을 제외하고, exec아직 반환, 반환 값을 무시 None항상. 따라서 문자열로 전달하지 않고 바이트 코드로 코드를 eval작성하면 명령문이있는 것을 실행할 수 있습니다 compile.

>>> eval(compile('if 1: print("Hello")', '<string>', 'exec'))
Hello
>>>

컴파일 된 코드에 문이 포함되어 있어도 문제없이 작동합니다. 이것은 None에서 반환 된 코드 객체의 반환 값이므로 여전히 반환합니다 compile.

에서 'eval'합니다 (에 따라서 모드 eval문자열이 전달되면 기능)는이 compile소스 코드를 진술 또는 하나의 표현을 넘어 다른 것을 포함 된 경우 예외가 발생 :

>>> compile('for i in range(3): print(i)', '<string>'. 'eval')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    for i in range(3): print(i)
      ^
SyntaxError: invalid syntax

더 긴 대답, 일명 gory 세부 사항

execeval

exec함수 ( Python 2의 명령문 )는 동적으로 작성된 명령문 또는 프로그램을 실행하는 데 사용됩니다.

>>> program = '''
for i in range(3):
    print("Python is cool")
'''
>>> exec(program)
Python is cool
Python is cool
Python is cool
>>> 

eval함수는에 대해 동일한 않는 하나의 표현 , 그리고 표현의 값을 반환합니다 :

>>> a = 2
>>> my_calculation = '42 * a'
>>> result = eval(my_calculation)
>>> result
84

exec그리고 eval둘 다 프로그램 / 표현식이 str, unicode또는 bytes소스 코드 를 포함 하는 code객체 또는 Python 바이트 코드를 포함 하는 객체 로 실행되도록 허용합니다 .

경우 str/ unicode/ bytes포함 된 소스 코드에 전달 exec, 그것은에 동등하게 동작합니다

exec(compile(source, '<string>', 'exec'))

eval유사하게 상응하는 동작 :

eval(compile(source, '<string>', 'eval'))

모든 표현식은 파이썬에서 명령문으로 사용될 수 있기 때문에 ( Expr파이썬 추상 문법 에서는 노드 라고 불리며 반대는 사실이 아닙니다), exec반환 값이 필요하지 않은 경우 언제든지 사용할 수 있습니다 . 말 즉, 당신도 사용할 수 있습니다 eval('my_func(42)')또는 exec('my_func(42)'), 그 존재의 차이 eval값에 의해 반환 반환 my_funcexec폐기를 :

>>> def my_func(arg):
...     print("Called with %d" % arg)
...     return arg * 2
... 
>>> exec('my_func(42)')
Called with 42
>>> eval('my_func(42)')
Called with 42
84
>>> 

2 중, 단지 exec문을 포함 소스 코드를 받아 같은 def, for, while, import, 또는 class, 할당 문 (일명 a = 42), 또는 전체 프로그램 :

>>> exec('for i in range(3): print(i)')
0
1
2
>>> eval('for i in range(3): print(i)')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    for i in range(3): print(i)
      ^
SyntaxError: invalid syntax

둘 다 execeval- 2 개 개의 추가 위치 인수 동의 globalslocals- 글로벌 및 로컬 변수는 코드가 보는 것을 스코프입니다. 받는 이러한 기본 globals()locals()라고하는 범위 내에서 exec또는 eval, 그러나 어떤 사전을 사용할 수에 대한 globals어떤 mapping위해 locals(포함 dict물론). 이것들은 코드가 보는 변수를 제한 / 수정하는 데 사용될뿐만 아니라 종종 executed 코드가 생성 하는 변수를 캡처하는 데에도 사용됩니다 :

>>> g = dict()
>>> l = dict()
>>> exec('global a; a, b = 123, 42', g, l)
>>> g['a']
123
>>> l
{'b': 42}

당신이 전체의 값을 표시하는 경우 ( g, 훨씬 더 길어질 수 있기 때문에 것입니다 execeval내장 기능과 같이 모듈 추가__builtins__ 가없는 경우 자동 전역에).

Python 2에서 exec명령문 의 공식 구문 은 실제로 다음 exec code in globals, locals과 같습니다.

>>> exec 'global a; a, b = 123, 42' in g, l

그러나 대체 구문 exec(code, globals, locals)도 항상 허용되었습니다 (아래 참조).

compile

compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)내장과 같은 코드의 반복 호출을 빠르게 할 수 있습니다 exec또는 eval에 소스를 컴파일하여 code사전 객체입니다. 이 mode매개 변수는 compile함수가 받아들이는 코드 조각 종류와 생성하는 바이트 코드 종류를 제어합니다. 선택 사항은 'eval', 'exec''single':

  • 'eval'mode는 단일 표현식을 기대하며, 실행될 때 해당 표현식 의 값을 리턴하는 바이트 코드를 생성 합니다 .

    >>> dis.dis(compile('a + b', '<string>', 'eval'))
      1           0 LOAD_NAME                0 (a)
                  3 LOAD_NAME                1 (b)
                  6 BINARY_ADD
                  7 RETURN_VALUE
  • 'exec'단일 표현식에서 전체 코드 모듈에 이르는 모든 종류의 파이썬 구성을 허용하고 마치 모듈 최상위 문장처럼 실행합니다. 코드 객체는 None다음을 반환합니다 .

    >>> dis.dis(compile('a + b', '<string>', 'exec'))
      1           0 LOAD_NAME                0 (a)
                  3 LOAD_NAME                1 (b)
                  6 BINARY_ADD
                  7 POP_TOP                             <- discard result
                  8 LOAD_CONST               0 (None)   <- load None on stack
                 11 RETURN_VALUE                        <- return top of stack
  • 'single'제한된 형태 'exec'포함하는 소스 코드를 허용하는 단일 (의해 분리 또는 여러 문장 문장 ;마지막 문 발현 문장 인 경우)에, 생성 된 바이트 코드는 지문 repr표준 출력이 식의 값을 (!) .

    if- elif- else체인과 루프 else, 그리고 try그와 함께 except, else그리고 finally블록은 하나의 문으로 간주됩니다.

    'single'파이썬 2에서는 때때로 코드에 여러 개의 최상위 문장을 허용 하는 버그가 있다는 점을 제외하고 2 개의 최상위 문장을 포함하는 소스 프래그먼트는 에러입니다 . 첫 번째 만 컴파일됩니다. 나머지는 무시됩니다.

    Python 2.7.8에서 :

    >>> exec(compile('a = 5\na = 6', '<string>', 'single'))
    >>> a
    5

    그리고 파이썬 3.4.2에서 :

    >>> exec(compile('a = 5\na = 6', '<string>', 'single'))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<string>", line 1
        a = 5
            ^
    SyntaxError: multiple statements found while compiling a single statement

    이것은 대화 형 파이썬 쉘을 만드는 데 매우 유용합니다. 그러나 결과 코드가 있더라도 표현식의 값은 반환되지 않습니다eval .

따라서 최대의 구분 execeval실제로는에서 온다 compile기능과 모드.


소스 코드를 바이트 코드로 컴파일하는 것 외에도 추상 구문 트리 (Python 코드의 구문 분석 트리)를 객체 로 compile컴파일하는 기능을 지원 합니다. 소스 코드를 추상 구문 트리로 변환합니다 ( Python으로 작성되고을 호출 함 ). 예를 들어 소스 코드를 즉석에서 수정하고 동적 코드를 생성하는 데 사용됩니다. 복잡한 경우에는 텍스트 줄 대신 노드 트리로 코드를 처리하는 것이 더 쉽기 때문입니다.codeast.parsecompile(source, filename, mode, PyCF_ONLY_AST)


동안 eval만 당신이 하나의 식을 포함하는 문자열을 평가할 수 있습니다, 당신이 할 수있는 eval전체 문장이나 된 경우에도 전체 모듈 compile바이트 코드로 거라고; 즉, Python 2에서는 print문장이며 eval직접적 으로 이끌 수 없습니다 .

>>> eval('for i in range(3): print("Python is cool")')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    for i in range(3): print("Python is cool")
      ^
SyntaxError: invalid syntax

compile그것으로 'exec'로 모드 code객체와 당신은 할 수 eval 그것을 ; 이 eval함수는을 반환 None합니다.

>>> code = compile('for i in range(3): print("Python is cool")',
                   'foo.py', 'exec')
>>> eval(code)
Python is cool
Python is cool
Python is cool

로 한 외모 경우 evalexecCPython의 3 소스 코드, 이것은 매우 분명하다; 둘 다 PyEval_EvalCode동일한 인수를 사용하여 exec명시 적으로 반환None 하는 유일한 차이점 입니다.

execPython 2와 Python 3 의 구문 차이

파이썬의 주요 차이점 중 하나 (2)exec진술하고 eval있는 내장 기능 (모두 내장되어 기능 파이썬 3). exec파이썬 2 의 공식 구문은 다음 과 같습니다 exec code [in globals[, locals]].

파이썬 2 대 3의 대다수는 달리 포팅 가이드가 보인다 제안execCPython과 2 문은 또한 구문을 사용할 수 있습니다 외모 정확히exec파이썬 3에서 함수 호출 파이썬 0.9.9가 있었다 이유는 것을 exec(code, globals, locals)내장을 기능적으로! 그리고 내장 함수는 Python 1.0 릴리스 이전의exec 문장 으로 대체 되었습니다 .

이 파이썬 0.9.9와 이전 버전과의 호환성을 아프게하지하는 것이 바람직 이었기 때문에, 귀도 반 로섬 (Guido van Rossum)은 1993 년에 호환성 해킹을 추가 한 다음이 경우 code길이가 2 또는 3의 튜플이고, globals그리고 locals에 전달되지 않은 exec가, 그렇지 않으면 문 code해석됩니다 것처럼 튜플의 2 층과 3 요소는했다 globalslocals각각. 호환성 1.4Python 1.4 문서 (가장 빠른 온라인 버전) 에서도 언급되지 않았습니다 . 따라서 포팅 가이드 및 도구의 많은 작가들에게 2012 년 11 월에 다시 문서화 될 때까지 알려지지 않았습니다 .

첫 번째 표현은 길이 2 또는 3의 튜플 일 수도 있습니다.이 경우 선택적 부분을 생략해야합니다. 양식 exec(expr, globals)은와 동일 exec expr in globals하지만 양식 exec(expr, globals, locals)은와 같습니다 exec expr in globals, locals. 튜플 형식은 명령문이 아닌 함수 인 execPython 3과의 호환성 을 제공 exec합니다.

그렇습니다. CPython 2.7에서는 실제로 20 년 동안 이전 버전과의 호환성을 위해 존재했을 때, 이전 버전과의 호환성 옵션 (이전 버전과의 호환성 옵션이있는 사람들을 혼동하는 이유)을 언급했습니다 .

따라서 while exec은 Python 1 및 Python 2의 명령문이고 Python 3 및 Python 0.9.9의 내장 함수입니다.

>>> exec("print(a)", globals(), {'a': 42})
42

널리 배포 된 모든 Python 버전에서 동일한 동작을 수행했습니다. 그리고 Jython 2.5.2, PyPy 2.3.1 (Python 2.7.6) 및 IronPython 2.6.1에서도 작동합니다 (CPython의 문서화되지 않은 동작에 밀접하게 적용됩니다).

호환성 해킹으로 Pythons 1.0-2.7에서 할 수없는 것은 반환 값을 exec변수 에 저장하는 것입니다 .

Python 2.7.11+ (default, Apr 17 2016, 14:00:29) 
[GCC 5.3.1 20160413] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = exec('print(42)')
  File "<stdin>", line 1
    a = exec('print(42)')
           ^
SyntaxError: invalid syntax

( exec항상을 반환하는 것처럼 Python 3에서는 유용하지 않습니다 None) 또는에 대한 참조를 전달하십시오 exec.

>>> call_later(exec, 'print(42)', delay=1000)
  File "<stdin>", line 1
    call_later(exec, 'print(42)', delay=1000)
                  ^
SyntaxError: invalid syntax

가능성이 거의 없지만 누군가가 실제로 사용한 패턴은 무엇입니까?

또는 목록 이해에 사용하십시오.

>>> [exec(i) for i in ['print(42)', 'print(foo)']
  File "<stdin>", line 1
    [exec(i) for i in ['print(42)', 'print(foo)']
        ^
SyntaxError: invalid syntax

이것은 목록 이해의 남용입니다 ( for루프를 대신 사용하십시오!).


이 되었습니까 [i for i in globals().values() if hasattr(i, '__call__')][0]문장이나 표현은? 그것이 표현이라면 왜 @데코레이터로 사용할 수 없습니까?
마리오

그것은 표현이다. 42또한 표현식이므로 @데코레이터로 사용할 수 없습니다 .
Antti Haapala

데코레이터 구문은 다음과 같습니다 decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE. 즉, 임의의 표현식을 데코레이터로 사용할 수 없으며, 점으로 구분되는 식별자와 선택적 호출 인수 만 사용할 수 있습니다.
Antti Haapala

1
과제의 오른쪽에 넣고 여전히 컴파일 할 수있는 것은 표현식이 아닙니다. 예를 들어, a = b = c오른쪽 b = c은 표현식이 아닌 완벽하게 유효한 명령문 입니다.
Tom

194
  1. exec파이썬 2.x의 문장과 파이썬 3.x의 함수는 표현이 아닙니다. 문자열에 포함 된 명령문 또는 명령문 세트를 컴파일하고 즉시 평가합니다. 예:

    exec('print(5)')           # prints 5.
    # exec 'print 5'     if you use Python 2.x, nor the exec neither the print is a function there
    exec('print(5)\nprint(6)')  # prints 5{newline}6.
    exec('if True: print(6)')  # prints 6.
    exec('5')                 # does nothing and returns nothing.
  2. eval내장 기능 (이다 없는 표현 반환 식을 생산하는 가치를 평가하는 문). 예:

    x = eval('5')              # x <- 5
    x = eval('%d + 6' % x)     # x <- 11
    x = eval('abs(%d)' % -100) # x <- 100
    x = eval('x = 5')          # INVALID; assignment is not an expression.
    x = eval('if 1: x = 4')    # INVALID; if is a statement, not an expression.
  3. compileexec및 의 하위 버전입니다 eval. 명령문이나 표현식을 실행하거나 평가하지 않지만이를 수행 할 수있는 코드 오브젝트를 리턴합니다. 모드는 다음과 같습니다.

    1. compile(string, '', 'eval')수행 한 코드 객체를 반환합니다 eval(string). 당신이주의 할 수없는 이 모드에서 문을 사용; (단일) 표현식 만 유효합니다.
    2. compile(string, '', 'exec')수행 한 코드 객체를 반환합니다 exec(string). 여기에서 원하는 수의 문장을 사용할 수 있습니다.
    3. compile(string, '', 'single')등이다 exec모드,하지만 첫 번째 문을 제외한 모든 것을 무시합니다. 결과가 포함 된 if/ else문은 단일 문으로 간주됩니다.

40
파이썬 3에서 exec()이제는 실제로 함수입니다.
Tim Pietzcker 2013

2
(당신이 지적했듯이), exec당신이 목표로하고있는 버전의 진술 이기 때문에, 그러한 괄호를 포함시키는 것은 기만적이며,을 사용하려고하면 in globals, locals버그도 있습니다.
Mike Graham

2
@MikeGraham exec 은 괄호와 파이썬 2의 호출과 같은 기능을 지원합니다 .
Antti Haapala

2
할당이 '괄호'를 지원하는 한 @AnttiHaapala는 할 수 있기 때문에 x = (y)사실 일 수도 있습니다. 또 다른 문장 전환 기능은 print; print(1, 2, 3)파이썬 2와 3 의 결과를 비교하십시오.
habnabit

1
@habnabit는 그렇지 않습니다. 내 답변 의 맨 아래를 읽고 놀라십시오.
Antti Haapala

50

exec는 진술 용이며 아무것도 반환하지 않습니다. eval은 표현 식용이며 expression의 값을 리턴합니다.

표현은 "무언가"를 의미하고 진술은 "무언가"를 의미합니다.


9
두 번째 단락은 그것이 거의 거짓말이되는 단순화입니다. 표현식은 함수 호출을 포함하면 무언가를 할 수 있습니다.
Antti Haapala
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.