Python exec()

时间:2020-02-23 14:42:41  来源:igfitidea点击:

Python exec()函数提供了对动态代码执行的支持。

Python exec()

Python exec()函数签名为:

exec(object, globals, locals)

对象–它应该是字符串或者代码对象。
如果是字符串,则将其解析为python语句块,然后执行它。

全局变量–用于指定可由exec()函数执行的全局函数。
它必须是字典。
如果未定义__builtins__,则所有内置函数均可用于exec函数。

locals –用于指定可用的局部函数和变量。
它可以是任何映射对象。
但是,字典最好与全局变量相似。

Python exec()函数返回None。
因此,它不能与return和yield语句一起使用。

Python exec()与eval()

Python exec()和eval()函数非常相似。
它们的用法和对动态代码执行的支持也非常相似。

但是,exec()和eval()函数之间存在一个主要区别。
Python exec()函数不返回任何内容,而eval()函数计算表达式并将值返回给调用代码。

Python exec()示例

让我们看一个简单的python exec()函数示例。

x = 1

exec('print(x==1)')

exec('print(x+2)')

输出:

True
3

Python exec()动态代码执行

让我们看另一个示例,用户将其中输入要由我们的程序执行的代码。

from math import *

for l in range(1, 3):

  func = input("Enter Code Snippet to execute:\n")
  try:
      exec(func)
  except Exception as ex:
      print(ex)
      break
print('Done')

示例输出:

Enter Code Snippet to execute:
print(sqrt(16))
4.0
Enter Code Snippet to execute:
print(min(2,1))
1
Done

请注意,我正在使用数学模块中的sqrt(),print()和min()是内置函数。

Python exec()安全风险

由于我们可以执行任何代码,因此存在与exec()函数相关的安全风险。
如果有人导入os模块并发出os.system('rm -rf /')命令,该怎么办?这将使我们的系统崩溃,因为所有文件都将被删除。
这是全局和局部参数派上用场以限制访问的时候。

Python exec()全局变量和局部变量

在决定exec()应该可用的功能之前,最好使用dir()函数获取可用功能和模块的列表。

from math import *

def square_root(n):
 return sqrt(n)

exec('print(dir())') # list of names in the current local scope

输出:

['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'square_root', 'tan', 'tanh', 'tau', 'trunc']

这有很多功能,包括内置模块,数学模块和我们定义的函数square_root。

让我们看看如果提供全局值作为空字典会发生什么情况。

exec('print(dir())',{})

输出:

['__builtins__']

因此,如果全局变量没有密钥,则可以使用内置函数。
让我们看看如何指定仅从内建模块访问某些功能的权限。

exec('print(min(1,2))',{"__builtins__":{"min": min, "print": print}}) #1

让我们看另一个示例,在该示例中我们将定义全局参数和局部参数值。

y=5
exec('print(y+1)',{"__builtins__": None}, {"y": y, "print": print}) # 6

让我们看一个最后的示例,在该示例中,我们将仅提供对一些数学模块功能的访问。

from math import *

for l in range(1, 3):
  func = input("Enter Code Snippet with Math Function to execute.\nFor Examples; print(squareRoot(x)) and print(pow(x,y)):\n")
  try:
      exec(func, {"squareRoot": sqrt, "pow": pow})
  except Exception as ex:
      print(ex)
      break
print('Done')

示例输出:

Enter Code Snippet with Math Function to execute.
For Examples; print(squareRoot(x)) and print(pow(x,y)):
print(squareRoot(100))
10.0
Enter Code Snippet with Math Function to execute.
For Examples; print(squareRoot(x)) and print(pow(x,y)):
print(max(2,4))
4
Done

我们可以指定一个自定义名称以使用任何函数进行映射,例如已经定义了squareRoot来映射到sqrt函数。

请注意,内置函数是可用的,因为我没有明确排除它们。
因此,定义exec()的更好方法是:

exec(func, {"squareRoot": sqrt, "pow": pow, "__builtins__": None, "print": print})

示例输出为:

Enter Code Snippet with Math Function to execute.
For Examples; print(squareRoot(x)) and print(pow(x,y)):
print(squareRoot(100))
10.0
Enter Code Snippet with Math Function to execute.
For Examples; print(squareRoot(x)) and print(pow(x,y)):
print(max(2,4))
'NoneType' object is not subscriptable
Done

现在出现错误,因为exec()函数无法访问max()函数。