zoukankan      html  css  js  c++  java
  • Python 语言中 eval 与 exec 的相同点和不同点

    相同点

    在 Python 中,eval 和 exec 都可以用来执行动态生成(dynamically generated)的代码。

    两者在Python 3中的函数声明基本相同,如下所示:

    eval(expression[, globals[, locals]])
    exec(object[, globals[, locals]])

    其中,输入参数中,globals 必须是字典(dict)类型,表示全局空间的变量,若未提供,则通过 globals() 方法获取全局变量,若提供的字典类型对象不包含名为 __builtins__ 的键,则会在表达式解析前,插入这个键,其值设为内置模块 builtins 的引用;而 locals 参数可以是任何可映射类型的对象,表示局部空间的变量,若未提供,则通过 locals() 方法获取局部变量。

    不同点

    下面从关键字类型、第一个输入参数、内调 compile 函数 这 3 个方面,讨论 eval 和 exec 的不同之处。

    1. 类型不同

    eval 在 Python 2 和 Python 3 中都是函数(function);而 exec 在 Python 2 中是语句(statement),在 Python 3 中是函数。

    2. 第一个输入参数不同

    eval 是 evaluate 的英文简写,只能用来计算单独一个 Python 表达式(expression)的值,返回值是这个表达式的执行结果;在 Python 中,表达式(expression)定义为可以在变量赋值中,进行赋值的对象:

    # An expression in Python is whatever you can have as the value in a variable assignment:
    a_variable = (anything you can put within these parentheses is an expression)

    而 exec 是 execute 的英文简写,用来执行 Python 语句(statement),如循环语句、try...except...异常处理语句、class 定义、函数定义等,无返回值,即返回值始终为 None。

    基本示例,如下所示:

    >>> 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

    3. compile 函数的模式不同

    eval 和 exec 在输入字符串类型时,内部都会首先调用 compile 函数编译为 bytecode,eval 函数对应的模式是 'eval',而 exec 对应的模式是 'exec'。compile 函数用来将输入参数 source 编译为 code 对象,具体声明如下:

    compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)

    其中,参数 source 通常为包含 Python 源码的字符串;参数 filename 应该给出从中读取代码的文件,或一些可识别的值,常常使用 '<string>' ;参数 mode 指定读取的代码的编译类型:如果包含多个语句,采用 'exec' 模式,如果只包含单一表达式,则采用 'eval' 模式;可选参数 flags 和 dont_inherit 用来控制 future 模块语句影响源码编译;参数 optimize 指定编译器的优化级别。更多内容参见 compile 官方文档

    采用 'exec' 模式的 compile 函数可以编译包含任意数量语句的源码为 bytecode,隐含返回值总是 None;而采用 'eval' 模式的 compile 函数只可以编译单一表达式为 bytecode,并返回这个表达式的值。如果在 'eval' 模式下,compile 函数的输入源码中包含语句或任何超出了单一表达式的要求,则会抛出 SyntaxError 异常。一些具体示例,如下:

    >>> eval(compile('20200926', '<string>', 'exec'))  # code returns None
    >>> eval(compile('20200926', '<string>', 'eval'))  # code returns 20200926
    20200926
    >>> exec(compile('20200926', '<string>', 'eval'))  # code returns 20200926,
    >>>                                          # but ignored by exec
    
    >>> 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 只接收单一表达式(eval accepts only a single expression),只是在字符串直接传递给 eval 函数时有效。此时内部会使用 compile(source, '<string>', 'eval') 编译为 bytecode。如果一个包含 bytecode 的 code 对象传递给 exec 或 eval ,它们的表现是相同,除了 exec 总是会返回 None。所以采用 eval 函数执行带有语句的字符串也是可以的,但需要首先使用 compile 函数将源码转为 bytecode,再传给 eval 方法。具体示例,如下:

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

    参考资料

    [1] The exec statement in Python 2. https://docs.python.org/2.7/reference/simple_stmts.html#exec

    [2] The exec function in Python 3. https://docs.python.org/3/library/functions.html#exec

    [3] The eval function in Python. https://docs.python.org/3/library/functions.html#eval

    [4] What's the difference between eval, exec, and compile? https://stackoverflow.com/questions/2220699/whats-the-difference-between-eval-exec-and-compile

  • 相关阅读:
    Magento安装教程
    让老婆爱你的十大方法。
    easy ui layout设计
    下交叉综合症
    fileloder.js+struts2实现文件异步上传,无页面刷新效果。
    将mysql中的Blob的图片在jsp中显示
    详解CSS样式的position属性
    Struts2与Spring的整合
    Play Framework常用标签list,set,如何遍历list、map类型数据
    我所理解的团队
  • 原文地址:https://www.cnblogs.com/klchang/p/13736133.html
Copyright © 2011-2022 走看看