
Python 中 pathlib.Path.glob() 返回的是惰性迭代器,一旦被部分消费(如内层循环 break 后),其状态不会自动重置;因此外层循环每次进入内层时,若 fileList2 定义在循环外,内层循环将从上一次中断位置继续,而非重新开始匹配。
python 中 `pathlib.path.glob()` 返回的是惰性迭代器,一旦被部分消费(如内层循环 `break` 后),其状态不会自动重置;因此外层循环每次进入内层时,若 `filelist2` 定义在循环外,内层循环将从上一次中断位置继续,而非重新开始匹配。
在处理成对 PDF 文件(如 xxx_text1.pdf 与 xxx_text2.pdf)合并任务时,一个常见却易被忽视的陷阱是:内层 for 循环未从头开始遍历匹配候选文件。根本原因在于 Path.glob() 返回的是单次使用的迭代器(iterator),而非可重复遍历的列表(list)或生成器(re-iterable generator)。
? 问题本质:迭代器耗尽不可回溯
原始代码中:
fileList1 = Path(folder).glob('*text1.pdf')
fileList2 = Path(folder).glob('*text2.pdf') # ← 定义在循环外!
for filename1 in fileList1:
for filename2 in fileList2: # ← 第二次迭代时,fileList2 已部分耗尽
if match(filename1, filename2):
merge(...)
break # ← 退出内层循环,但 fileList2 的迭代器位置已前移
由于 fileList2 是一次性迭代器,首次外层循环执行后,内层循环可能已消费了前几个 *text2.pdf 项;当第二次进入外层循环时,for filename2 in fileList2 并不会“重播”,而是继续从上次停止处读取——导致后续匹配失败或跳过正确配对。
✅ 正确解法:每次外层迭代都重建内层迭代器
将 fileList2 的创建移入外层循环体内,确保每次匹配都面对一个全新的、从头开始的迭代器:
def mergeFiles(folder):
folder = os.path.abspath(folder)
fileList1 = Path(folder).glob('*text1.pdf')
outputFolderPath = Path(folder) / 'somefolder'
outputFolderPath.mkdir(exist_ok=True)
n = 0
folder_len = len(folder) + 1
file_name_area = folder_len + 12
print(f'Adding files in {outputFolderPath}...')
for filename1 in fileList1:
n += 1
# ✅ 关键修复:每次外层迭代都新建 fileList2 迭代器
fileList2 = Path(folder).glob('*text2.pdf')
for filename2 in fileList2:
# 提取用于匹配的标识字符串(如 r01_cz14_028_city)
key1 = str(filename1)[folder_len:file_name_area].lower()
key2 = str(filename2)[folder_len:file_name_area].lower()
if key1 == key2:
# 构造输出文件名(示例逻辑)
output_name = (
'D' +
str(filename1)[folder_len + 4: folder_len + 6].upper() + '_' +
str(filename1)[folder_len + 9: folder_len + 12] + '_text3.pdf'
)
output_path = outputFolderPath / output_name
pdfMerge([str(filename1), str(filename2)], str(output_path))
print(f'{n}. {output_name}')
break # 匹配成功即退出内层,避免冗余遍历
else:
print(f'{n}. Warning: No matching text2.pdf found for {filename1.name}')
print('Done.')
⚠️ 注意事项与最佳实践
-
勿混淆
glob()与list():list(Path(...).glob(...))可获得可重复遍历的列表,但会一次性加载所有路径到内存——对海量文件不友好;而重建glob()迭代器更省内存且语义清晰。 -
路径操作推荐
pathlib:使用Path / 'subdir'和.mkdir(exist_ok=True)替代字符串拼接与os.makedirs(),更安全、跨平台。 -
增强健壮性:添加
else子句(与for配合)可捕获未匹配情况;建议用pathlib.Path处理路径,避免 Windows 反斜杠转义问题。 -
性能提示:若文件数量极大(如数千对),可预先构建
text2文件的字典索引({key: path}),将时间复杂度从 O(n×m) 降至 O(n),但本场景下简洁性优先。
通过理解 Python 迭代器的“一次性”特性,并将内层数据源置于正确的作用域内,即可彻底解决嵌套循环中“第二层不从头开始”的逻辑陷阱。










