Python中如何不用eval实现字符串形式的列表切片/访问操作?
替代eval实现字符串形式的列表切片/访问
需求:将字符串形式的列表访问(或切片)规范,例如"[1]"、"[3:2]"或"[:-4]",应用到Python中的现有列表,但不想使用不安全的eval函数,同时避免自行解析字符串(比如正则无法匹配负数的问题)。
原实现(使用eval):
import sys mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] myargspec = sys.argv[1] if len(sys.argv) > 1 else "" print(f"Got command line argument: '{myargspec}'") mylist_sliced_str = f"mylist{myargspec}" print(f"... attempting to access: '{mylist_sliced_str}'") mylist_sliced = eval(mylist_sliced_str) print(f"... result: {mylist_sliced}")
运行示例:
$ python3 test.py Got command line argument: '' ... attempting to access: 'mylist' ... result: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] $ python3 test.py "[2]" Got command line argument: '[2]' ... attempting to access: 'mylist[2]' ... result: 3 $ python3 test.py "[2:4]" Got command line argument: '[2:4]' ... attempting to access: 'mylist[2:4]' ... result: [3, 4] $ python3 test.py "[:-4]" Got command line argument: '[:-4]' ... attempting to access: 'mylist[:-4]' ... result: [1, 2, 3, 4, 5, 6]
安全替代方案:使用ast模块解析索引/切片
可以利用Python内置的ast模块来安全解析字符串形式的索引或切片表达式,它只会处理合法的语法结构,不会执行任意代码,完美规避eval的安全风险,同时无需手动解析字符串。
实现代码:
import sys import ast from operator import getitem mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] myargspec = sys.argv[1] if len(sys.argv) > 1 else "" print(f"Got command line argument: '{myargspec}'") if not myargspec: # 空参数直接返回原列表 result = mylist else: # 构造合法的表达式用于解析,比如"x[2:4]" expr_str = f"x{myargspec}" try: # 解析表达式为抽象语法树 tree = ast.parse(expr_str, mode='eval') subscript_expr = tree.body if isinstance(subscript_expr, ast.Subscript): # 安全解析切片/索引对象 slice_or_index = ast.literal_eval(subscript_expr.slice) # 执行列表访问/切片 result = getitem(mylist, slice_or_index) else: raise ValueError("Invalid subscript expression format") except Exception as e: print(f"Error parsing spec: {str(e)}") sys.exit(1) print(f"... result: {result}")
方案说明:
- 利用
ast.parse将构造的表达式(如x[-1]、x[::2])解析为抽象语法树,确保只处理合法的下标访问语法 - 通过
ast.Subscript判断表达式类型,再用ast.literal_eval安全提取切片或索引值,支持所有Python合法的切片格式(包括负数、步长) - 使用
operator.getitem执行列表的下标/切片操作,和直接编写mylist[slice_obj]效果完全一致 - 空参数逻辑与原实现保持一致,返回完整列表
测试验证:
$ python3 test.py "[-1]" Got command line argument: '[-1]' ... result: 10 $ python3 test.py "[5:-2]" Got command line argument: '[5:-2]' ... result: [6, 7, 8] $ python3 test.py "[::2]" Got command line argument: '[::2]' ... result: [1, 3, 5, 7, 9]
内容的提问来源于stack exchange,提问作者sdbbs
相关产品推荐
相关产品推荐

