在 Python 中,exec()
是一个内置函数,用于动态执行 Python 代码。代码可以是字符串形式,exec()
会将其解析并执行为 Python 语句。它的主要用途是运行动态生成的代码或在运行时执行用户提供的代码。以下是对 exec()
的详细介绍以及几个有特点的示例。
exec()
的基本用法
语法:
exec(code, globals=None, locals=None)
- code:要执行的 Python 代码,可以是字符串或编译后的代码对象。
- globals(可选):一个字典,表示全局命名空间。如果提供,代码将在这个命名空间中执行。
- locals(可选):一个字典,表示局部命名空间。如果提供,代码将在这个命名空间中访问局部变量。
- 返回值:
exec()
始终返回None
,它直接执行代码而不返回值。
注意事项:
exec()
可以执行任意 Python 代码(如定义函数、类、循环等),但代码的安全性需要特别注意,因为它可能执行恶意代码。- 使用
globals
和locals
参数可以控制代码的执行环境,限制变量的作用范围。 - 异常处理通常与
exec()
一起使用,以捕获代码执行中的错误。
exec()
的特点与示例
以下是几个展示 exec()
特点的示例,涵盖常见用途和注意事项。
示例 1:动态执行简单的数学表达式
code = "result = 2 + 3 * 4"
exec(code)
print(globals().get("result")) # 输出:14
特点:
exec()
执行字符串形式的表达式,结果存储在全局命名空间。- 通过
globals().get()
获取执行后定义的变量。 - 适合动态计算简单的用户输入。
示例 2:定义和调用函数
code = """
def greet(name):
return f'Hello, {name}!'
print(greet('Alice'))
"""
exec(code) # 输出:Hello, Alice!
特点:
exec()
可以执行复杂的代码块,如函数定义。- 执行的函数会立即运行,并产生输出。
- 适合动态生成和调用函数。
示例 3:限制执行环境
restricted_globals = {"__builtins__": None} # 禁用内置函数
restricted_locals = {}
code = """
x = 10
print(x) # 错误,因为 print 被禁用
"""
try:
exec(code, restricted_globals, restricted_locals)
except NameError as e:
print(f"错误:{e}") # 输出:错误:name 'print' is not defined
print(restricted_locals.get("x")) # 输出:10
特点:
- 通过设置
globals
和locals
,限制代码的访问权限(禁用print
等内置函数)。 - 代码执行结果存储在
locals
中,可以安全提取。 - 适合需要沙箱环境的场景(如用户代码执行)。
示例 4:动态生成类
code = """
class Person:
def __init__(self, name):
self.name = name
def introduce(self):
return f'My name is {self.name}'
p = Person('Bob')
print(p.introduce())
"""
exec(code) # 输出:My name is Bob
特点:
exec()
支持定义和实例化类,展示其处理复杂代码的能力。- 适合运行时生成类或模块。
示例 5:处理用户输入(类似提供的代码)
while True:
code = input("请输入 Python 代码(输入 exit 退出):\n>>> ")
if code.lower() == "exit":
break
try:
exec(code, {"__builtins__": {}}, {}) # 限制内置函数
except Exception as e:
print(f"执行错误:{e}")
特点:
- 模仿
python_execute.py
的交互式执行,允许用户输入代码。 - 使用空的
globals
和locals
限制环境,增强安全性。 - 捕获异常以提供用户友好的错误提示。
exec()
的注意事项与安全建议
安全性:
exec()
执行任意代码,可能导致安全风险(如删除文件、访问网络)。- 永远不要在不受信任的环境中直接运行用户输入的代码。
- 使用
restricted_globals
和restricted_locals
限制内置函数和模块访问,或者使用第三方沙箱库(如PyPy
的沙箱模式)。
性能:
exec()
动态解析代码,效率低于直接编写的 Python 代码。- 对于频繁执行的代码,考虑预编译为代码对象(使用
compile()
)。
调试:
exec()
执行的代码可能难以调试,因为错误信息可能指向字符串而不是文件。- 建议记录输入代码以便追踪问题。
替代方案:
- 对于简单的表达式,使用
eval()
(仅计算表达式并返回值)。 - 对于复杂逻辑,优先编写静态代码或使用插件系统。
- 对于简单的表达式,使用
可执行的例子
简单版
简单的执行,可执行很多高危命令:
def simple_exec():
while True:
code = input("请输入要执行的Python代码:\n>>> ")
if code.lower() in ("exit", "quit"):
break
try:
exec(code)
except Exception as e:
print(f"执行错误:{e}")
simple_exec()
这就很危险,比如用户写:
import os
os.system('rm -rf /')
就能直接删光你的服务器!!
限制版
def main():
restricted_globals = {"__builtins__": dict(__builtins__)}
restricted_locals = {}
test_codes = [
# 能成功执行
"print('Hello')",
"x = 5\ny = x * 2\nprint(y)",
"for i in range(3):\n print(i)",
"# 注释",
"pass",
# 会报错
"print(undefined)",
"for x in __builtins__:\n print(x)", # 不会报 'module' 错误,但迭代键
]
for code in test_codes:
print(f"\n测试代码:\n{code}")
try:
exec(code, restricted_globals, restricted_locals)
print(f"locals: {restricted_locals}")
except Exception as e:
print(f"错误: {e}")
restricted_locals.clear() # 重置 locals