解析Python中的eval()、exec()及其相关函数

  

解析Python中的eval()、exec()及其相关函数

Python中有三个内置函数eval()exec()compile()来执行动态代码。这些函数能够从字符串参数中读取Python代码并在运行时执行该代码。但是,使用这些函数时必须小心,因为它们的不当使用可能会导致安全漏洞。

eval()

eval()函数可解析一个字符串表达式,并返回表达式的计算结果。该函数接受可选的globalslocals参数,用于指定在编译时使用的全局和局部命名空间。

>>> x = 5
>>> y = 10
>>> eval('x + y')
15

注意:

  • eval()函数执行的代码是不受限制的,因此请勿使用它来解析未知来源的字符串。
  • 可以通过在字符串开始处添加“-”符号,在eval()函数中执行负数计算。然而,该实现也可能会导致计划外的代码执行和安全漏洞。

exec()

exec()函数也可解析一个字符串表达式,但不返回任何值。该函数同样接受可选的globalslocals参数。

>>> program = 'print("Hello, World!")'
>>> exec(program)
Hello, World!

compile()

compile()是一个内置函数,将Python源代码编译为字节代码AST对象,不会执行该代码。编译后的代码通过eval()exec()函数执行。它的用法如下:

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

该函数共有6个参数:

  • source - 必需,要被编译的源代码字符串,或者以\n分割的代码行的元组、列表。还可以传入AST对象。
  • filename - 必需,代码所在文件名称,如果代码不是从文件读取,则可以使用任何名称。
  • mode - 必需,指定编译代码的种类。取值为exec表示代码将被编译为可执行的代码,取值为eval表示代码将被编译为一个单一的表达式,如果代码中包含换行,则会抛出语法错误,取值为singe表示代码预期来自单个交互输入,需要使用类似于REPL的方式来执行该代码。
  • flags - 可选,可以用来声明变量全局命名空间和本地命名空间(与exec()中的globalslocals参数相同)。同时,还可以使用其他标志,例如与调试相关的标志。
  • dont_inherit - 可选,默认值为False,指定在复制其父级的标志和作用域(模块或类)时是否跳过指定模块或类。当编写一系列嵌套的类或函数时,这个选项非常有用。
  • optimize - 可选,默认值为-1,可以通过0、1或2来指定优化级别。优化等级越高,执行的代码速度越快,但是编译过程的时间也会更长。
>>> source = """
... def say_hello(name):
...     print("Hello, " + name + "!")
...
... say_hello("World")
... """
>>> code = compile(source, "<string>", "exec")
>>> exec(code)
Hello, World!

注意:

  • 在使用compile()时,需要明确了解编译代码的风险。

示例说明

示例1:使用eval()执行简单的数学表达式

下面是如何使用eval()计算简单的数学表达式的示例:

calculation = input("Enter a calculation: ")
result = eval(calculation)
print("Result:", result)

运行该程序,会提示用户输入一个简单的数学表达式,例如:3 + 4 * 5,程序将计算结果并打印出来。

示例2:使用compile()exec()编译和执行Python代码

下面是如何使用compile()exec()编译和执行Python代码的示例:

code = """
def say_hello(name):
    print("Hello, " + name + "!")
"""

compiled_code = compile(code, "<string>", "exec")
exec(compiled_code)

say_hello("World")

运行该程序,将输出Hello, World!的结果。

相关文章