df.query()字符串需用反引号包裹含特殊字符列名、@引用外部变量、双引号套单引号写字符串值、用&|~代替and/or/not并加括号,且不支持索引条件、MultiIndex、正则及groupby.filter()等场景。

df.query() 的字符串表达式怎么写才不报错
直接用 df.query('age > 18') 看似简单,但一换字段名或加空格就容易报 UndefinedVariableError 或 SyntaxError。根本原因是 query 把字符串当 Python 表达式解析,但变量作用域和命名规则和普通代码不同。
- 列名含空格、点号、连字符(如
'user name'、'user.age'、'is-active')必须用反引号包裹:df.query('`user name` > 25') - 不能直接用 Python 变量,得用
@前缀引用外部变量:threshold = 18; df.query('age > @threshold') - 字符串值要用双引号套单引号,或转义:正确是
df.query("name == 'Alice'"),错的是df.query('name == 'Alice'')(引号嵌套混乱) - 布尔运算符必须用英文:用
&、|、~,不是and、or、not;且必须加括号避免优先级问题:df.query('(age > 18) & (city == "Beijing")')
query 和布尔索引(df[...])到底该选哪个
两者都能筛数据,但行为和性能差异不小。query 更适合复杂条件拼接和可读性,但底层仍转成布尔索引执行;而直接用 df[...] 更透明、调试方便,且支持任意 Python 表达式(比如调用自定义函数)。
- query 不支持链式方法调用中的原地修改(比如
df.query(...).loc[:, 'x'] = 1可能触发 SettingWithCopyWarning) - query 对缺失值(NaN)默认跳过,而
df[...]会保留布尔数组里的False和NaN,结果长度一致 - 大数据集下 query 有轻微解析开销,但通常可忽略;若频繁调用且条件固定,预编译成布尔掩码(
mask = df.age > 18)再复用更快 - query 无法访问行索引做条件(如
df.query('index > 10')不行),得先重置索引或改用df.iloc[10:]
query 中怎么安全引用列名和外部变量
列名冲突和变量注入是最常踩的坑。query 会优先在 DataFrame 列中找名字,找不到才去全局/局部作用域查,所以列名别和内置函数(如 sum、min)或变量同名。
- 列名是 Python 关键字(如
class、def)必须加反引号:df.query('`class` == "A"') - 外部变量名如果和列名重复,@ 语法仍有效,但逻辑易混淆,建议变量名加前缀(如
min_age = 18而非age = 18) - 想用列表做 in 查询,用
in+@:valid_cities = ['Beijing', 'Shanghai']; df.query('city in @valid_cities') - 正则匹配用
str.contains()方法,不能直接写在 query 字符串里:df[df.city.str.contains('jing')],query 不支持该语法
query 在 groupby 或多级索引场景下的限制
query 设计初衷是单层 DataFrame 的快速筛选,遇到分组后对象或 MultiIndex 就容易失效或行为反直觉。
-
groupby().apply()里用df.query()没问题,但groupby().filter()不接受 query 字符串,只能传函数 - MultiIndex 列需用元组形式引用,但 query 不支持;例如列是
('sales', '2023'),不能写df.query('("sales", "2023") > 100'),得先df.columns = ['_'.join(c) for c in df.columns]扁平化 - query 不支持对索引列直接条件(除非先
reset_index()),而df.loc[df.index > '2023-01-01']这种更直接 - query 返回新 DataFrame,不会影响原数据;但如果原 df 是视图(比如切片得来),query 结果可能仍是视图,赋值时小心
SettingWithCopyWarning
真正麻烦的地方不在语法多难,而在它看起来像 SQL,实际却受限于 Python 解析器和 pandas 内部符号表——写之前先问一句:这个条件,我能不能用普通布尔索引一行写完?如果能,往往更稳。

















