You need to enable JavaScript to run this app. Python递归函数查找Excel最近匹配日期时触发递归深度超限
优惠活动
大模型
产品
解决方案
定价
更多

Python递归函数查找Excel最近匹配日期时触发递归深度超限

问题根因排查

两个核心问题共同导致了异常:

  • 递归返回值缺失:find_closest_date函数中,未匹配到当前日期的递归分支没有加return关键字。递归触达最内层找到匹配日期后,返回值无法逐层向上传递,外层函数只会返回None,逻辑完全断裂。
  • 一次性生成器耗尽:openpyxl使用read_only=True加载文件时,ws.rows是只能迭代一次的生成器。第一次调用find_date遍历完所有行后,生成器就被完全耗尽,后续递归调用传入的wsRows没有可迭代内容,永远匹配不到日期,最终无限递归触发栈溢出。
可行解决方案

优化版(推荐,性能与稳定性最优)

不再每次遍历工作表查找日期,提前遍历一次构建日期-行号映射字典,查找效率从O(n)降至O(1),同时彻底规避生成器耗尽问题,还避免了递归栈溢出风险。

import openpyxl
from datetime import datetime, timedelta

def preload_date_map(ws):
    # 提前遍历一次工作表,构建日期-行号映射字典
    date_map = {}
    for row in ws.iter_rows():
        for cell in row:
            # 只匹配datetime类型单元格,避免误匹配其他值
            if isinstance(cell.value, datetime):
                # 同一行多个日期时保留第一个匹配的行号
                date_map.setdefault(cell.value, cell.row)
    return date_map

def find_closest_date(target_date, date_map, search_type, max_offset=365):
    # search_type=0 查找过去最近日期,1 查找未来最近日期
    current_date = target_date
    offset_step = -1 if search_type == 0 else 1

    # 增加最大查找范围限制,避免极端情况无限循环
    for _ in range(max_offset):
        if current_date in date_map:
            return date_map[current_date]
        current_date += timedelta(days=offset_step)
    # 超出查找范围仍未匹配到则返回-1
    return -1


if __name__ == "__main__":
    startDate = datetime.strptime('2021-01-18', '%Y-%m-%d')
    endDate = datetime.strptime('2021-02-16', '%Y-%m-%d')

    wb = openpyxl.load_workbook('C:\\PATH\\TO\\FILE.xlsx', read_only=True)
    ws = wb['SHEET']

    # 提前加载日期映射表,仅遍历一次工作表
    date_map = preload_date_map(ws)

    # 原有直接查找逻辑可直接通过字典取值完成
    print(str(startDate) + " (" + str(type(startDate)) + ") " + str(date_map.get(startDate, -1)))
    print(str(endDate) + " (" + str(type(endDate)) + ") " + str(date_map.get(endDate, -1)))

    # 查找过去最近的日期,默认最多前后追溯365天,可自定义调整范围
    print(find_closest_date(endDate, date_map, search_type=0))

    wb.close()

最小改动版(保留原有代码结构)

如果不想改动原有函数逻辑,仅需两处调整即可运行:

  1. 递归分支补充return关键字
  2. 将一次性生成器转为列表传入,避免迭代后耗尽

修改后的find_closest_date函数:

def find_closest_date(date, wsRows, searchType):
    result = find_date(date, wsRows)
    if result == -1:
        nextDate = date
        if searchType == 0:
            nextDate -= timedelta(days=1)            
        else:
            nextDate += timedelta(days=1)
        # 补充return,将递归结果逐层向上传递
        return find_closest_date(nextDate, wsRows, searchType)
    else:
        return result 

调用时不要直接传ws.rows生成器,需转为列表:

print(find_closest_date(endDate, list(ws.rows), 0))

注意:该版本仍存在每次查找全表遍历的性能问题,数据量较大时运行速度会明显变慢,优先推荐使用预加载字典的优化版本。

内容的提问来源于stack exchange,提问作者Mariano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.02 15:54:04