
在无第三方库(如 pandas、SQLAlchemy)的前提下,利用 Python 标准库中的 eval() 可安全、灵活地对列表数据执行类似 SQL 的动态条件过滤,适用于 CSV 解析后结构化数据的即席查询。
在无第三方库(如 pandas、sqlalchemy)的前提下,利用 python 标准库中的 `eval()` 可安全、灵活地对列表数据执行类似 sql 的动态条件过滤,适用于 csv 解析后结构化数据的即席查询。
当处理来自 CSV 文件的异构、易变结构数据时,硬编码查询逻辑会迅速失效——业务字段增减、条件组合变化频繁,亟需一种可配置、可扩展的运行时查询机制。Python 标准库虽不提供内置的“SQL 引擎”,但通过谨慎封装 eval(),我们能构建一个轻量、通用且表达力强的查询函数。
核心思路是:将每行数据(如元组或列表)作为 row 变量传入动态表达式上下文,由 eval() 解析并求值布尔条件。为兼顾安全性与灵活性,我们限制其作用域,仅暴露必要内置函数和类型检查工具:
from collections.abc import Sequence
from typing import Any, Tuple, List
def query_data(
data: Sequence[Tuple[Any, ...]],
condition: str,
*,
safe_builtins: bool = True
) -> List[Tuple[Any, ...]]:
"""
基于动态条件字符串对数据行进行过滤。
Args:
data: 行数据序列,每行应为 tuple 或 list
condition: 合法 Python 表达式,其中 'row' 代表当前行(索引访问如 row[0], row[2])
safe_builtins: 是否启用受限内置函数(推荐 True)
Returns:
满足条件的行组成的列表
"""
# 安全的内置函数白名单(避免 exec/compile 等危险操作)
allowed_builtins = {
'len': len,
'isinstance': isinstance,
'type': type,
'str': str,
'int': int,
'float': float,
'bool': bool,
'None': None,
'True': True,
'False': False,
} if safe_builtins else {}
return [
row for row in data
if eval(condition, {"__builtins__": allowed_builtins}, {"row": row})
]
✅ 典型用法示例(假设已用 csv.reader 加载为元组列表):
import csv
from io import StringIO
# 模拟 CSV 数据
csv_text = """name,age,city,score,active
Alice,28,Beijing,85.5,True
Bob,34,Shanghai,92.0,False
Charlie,22,Guangzhou,76.5,True
Daniel,,Shenzhen,88.0,True"""
csv_data = list(csv.reader(StringIO(csv_text)))[1:] # 跳过表头
# → [('Alice', '28', 'Beijing', '85.5', 'True'), ...]
# 动态查询:年龄 > 25 且活跃状态为 True
result = query_data(csv_data, 'int(row[1]) > 25 and row[4] == "True"')
# → [('Alice', '28', 'Beijing', '85.5', 'True'), ('Daniel', '', 'Shenzhen', '88.0', 'True')]
# 更复杂条件:城市以 'B' 开头,且分数不低于 90(需类型转换)
result = query_data(csv_data, 'row[2].startswith("B") and float(row[3]) >= 90.0')
# → [('Bob', '34', 'Shanghai', '92.0', 'False')]
⚠️ 重要注意事项:
- 安全性第一:eval() 仅限可信上下文(如内部管理后台、离线脚本)。若条件来自用户输入,必须严格校验或改用 AST 解析器(如 ast.literal_eval + 自定义条件解析器)替代;
- 空值处理:CSV 中缺失值常为 '' 或 'None' 字符串,非 Python None,建议预处理统一为空值或使用 row[i] or None 等逻辑;
- 类型转换显式化:eval 不自动转换类型,row[1] > 25 在字符串 "28" 上会报错,务必用 int(row[1]) 或 float(row[3]) 显式转换;
-
性能考量:对大数据集(>10k 行),eval 开销略高;如需高频查询,可预先编译表达式(compile(condition, "
", "eval"))复用 code 对象。
该方案本质是将查询逻辑“外置”为字符串配置,解耦业务规则与代码,完美契合需求中“查询模式不可预知、条件随时变更”的场景。它不是替代 SQL 的全功能引擎,而是在标准库约束下最简、最直接、最可控的动态过滤实现。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











