登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  python教程

Python 3.14 fnmatch.filterfalse怎样筛掉匹配文件

来源:17golang原创

时间:2026-11-15 15:58:49 133浏览 收藏

如果手里已经有一组文件名,只想把匹配 *.pyc 或 *.tmp 的项目排除掉,Python 3.14 可以直接使用 fnmatch.filterfalse(names, pattern)。它接收字符串列表和一个 shell 风格通配符,返回“不匹配”该模式的字符串列表;想保留匹配项时,仍然使用 fnmatch.filter()。

官方地址:https://docs.python.org/3.14/library/fnmatch.html

这个 API 只负责匹配字符串,不会删除文件,也不会递归扫描目录。下面从最小写法开始,把返回方向、多个模式、大小写和旧版本兼容边界一次说明白。

分清 filter 与 filterfalse 的保留方向

两者的输入形式相同,区别只在于返回哪一侧:

  • fnmatch.filter(names, pattern):保留匹配模式的名称。
  • fnmatch.filterfalse(names, pattern):排除匹配模式的名称,保留其余名称。

可以把它们理解为同一组匹配关系的两种取集合方式。不要因为函数名里有 false 就把它当成返回布尔值;它返回的仍然是一个列表。

Python fnmatch filter 与 filterfalse 的匹配保留和排除关系说明图
图1:静态说明 filter 与 filterfalse 的返回方向差异,不是运行截图。

用单个通配符排除文件名

下面的例子把缓存字节码文件从待处理清单中去掉。注释说明了输入、匹配方向和结果的用途:

from fnmatch import filterfalse

# 这是已经得到的文件名清单;filterfalse 只处理字符串,不操作磁盘。
names = ["main.py", "cache.pyc", "README.md", "worker.py"]

# 排除所有以 .pyc 结尾的名称,返回其余名称。
source_files = filterfalse(names, "*.pyc")

print(source_files)

调用的第二个参数是 shell 风格模式,而不是完整正则表达式。常见规则包括:

模式含义例子
*匹配任意长度的字符*.tmp
?匹配一个字符part?.csv
[seq]匹配序列中的一个字符report[0-9].txt
[!seq]匹配不在序列中的一个字符part[!0].csv

返回值可以继续传给后续函数,也可以显式转成列表保存。它不会根据后缀删除真实文件,因此把结果交给 os.remove() 之前仍需由业务代码决定是否允许删除。

处理多个模式与路径大小写

filterfalse() 一次接收一个模式。需要同时排除多个后缀时,推荐先明确“任一模式命中就排除”的集合语义,再保留未命中的名称:

from fnmatch import fnmatch, filterfalse

# 这些名称来自上一步或目录遍历结果;本例只演示字符串过滤。
names = ["app.py", "app.pyc", "debug.tmp", "notes.txt", "BUILD.TMP"]
excluded_patterns = ("*.pyc", "*.tmp")

# 任一模式匹配就进入排除集合;fnmatch 使用 shell 风格通配符。
excluded = [
    name for name in names
    if any(fnmatch(name, pattern) for pattern in excluded_patterns)
]

# 用排除集合构造保留集合,避免把“多个模式”误写成一次 filterfalse 调用。
kept = [name for name in names if name not in excluded]
print(kept)

如果模式数量很少,这种写法最容易读懂;如果需要保持原始顺序,列表推导会自然保留 names 的顺序。不要把多个模式拼成一个正则表达式再传给 filterfalse(),因为 fnmatch 的语法与正则表达式不是一套规则。

Python fnmatch.filterfalse 的多个模式和大小写边界说明图
图2:静态说明多个模式和匹配规则的边界,不是运行截图。

大小写行为还要看平台的规范化规则。官方文档说明,fnmatch() 会使用 os.path.normcase() 做大小写规范化,而 fnmatchcase() 强制区分大小写。若业务要求跨平台结果稳定,可以显式选择 fnmatchcase(),不要把开发机上的大小写表现当成所有系统都一样。

兼容没有 filterfalse 的 Python 版本

filterfalse() 是 Python 3.14 在 fnmatch 模块中新增的反向过滤入口。如果项目仍需要运行在更早版本,可以用 fnmatch() 组合补集:

from fnmatch import fnmatch

def exclude_matches(names, pattern):
    # 兼容旧版本:只保留“不匹配”模式的名称,语义等价于 filterfalse。
    return [name for name in names if not fnmatch(name, pattern)]

names = ["main.py", "cache.pyc", "README.md"]
clean_names = exclude_matches(names, "*.pyc")
print(clean_names)

如果只支持 Python 3.14 及以上版本,直接导入 filterfalse 更能表达意图;如果是公共库或插件,兼容函数可以集中放在适配层,避免项目各处重复写列表推导。

什么时候不要用 filterfalse

这个函数适合“已有字符串集合 + 一个 shell 风格模式”的过滤任务,下面几种情况应换工具:

  • 需要递归查找目录、处理权限或跳过符号链接时,用 pathlib.Path.rglob() 等目录 API,再把名称过滤作为单独一步。
  • 需要复杂捕获组、量词或边界断言时,用 re;不要把正则表达式直接传给 fnmatch。
  • 需要删除、移动或改名时,把过滤结果交给明确的文件操作函数,并在业务层处理异常和回滚。
  • 需要保留匹配项时用 filter(),不要先调用 filterfalse() 再手动求补集。

速查表:按目标选调用方式

目标推荐写法关键边界
保留匹配项fnmatch.filter(names, pattern)一次处理一个模式
排除匹配项fnmatch.filterfalse(names, pattern)Python 3.14 新入口
旧版本排除匹配项[n for n in names if not fnmatch(n, pattern)]可封装成兼容函数
强制区分大小写fnmatchcase(name, pattern)不依赖平台规范化表现
复杂文本规则re正则语法不能直接当 fnmatch 模式

记住一个判断就够了:filter() 是“留下命中的”,filterfalse() 是“留下没命中的”。多模式场景先写清楚“任一模式命中是否排除”,再决定是用列表推导组合 fnmatch(),还是把任务拆成多个清晰的过滤阶段。

相关问题

  • filterfalse 会删除硬盘上的文件吗?不会,它只返回新的字符串列表。
  • 能否一次把多个模式传给 filterfalse?不能。需要多个模式时,先用 fnmatch() 组合条件,或分阶段过滤。
  • 为什么同一个模式在不同系统上大小写结果不同?普通 fnmatch() 会结合平台的 normcase() 规则;严格区分大小写时使用 fnmatchcase()。
声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>