Python使用holidays库生成2005年节假日列表时函数崩溃原因
问题排查与修复方案
报错根本原因
holidays库提供的UnitedStates节假日实例并非静态字典,内部实现了惰性加载逻辑:部分节假日不会在类初始化阶段完成计算写入,而是在用户首次通过[date]语法访问对应日期的节日名称时,才会动态计算该节日并写入实例的字典结构中。
你在列表推导式中同时执行遍历实例和访问实例key取节日名两个操作,遍历过程中访问key触发了新条目写入,导致字典大小在迭代时发生变化,抛出对应运行时错误。2005年无特殊属性,仅刚好触发了该版本holidays库美国节假日的惰性加载逻辑,其余年份的节假日在初始化阶段已全部加载完成,访问key不会修改字典结构,因此无报错。
隐藏隐患
你代码中列表推导式的临时变量名与函数入参date重名,会在推导式作用域内覆盖入参值,属于潜在逻辑错误,需要修正。
修复代码
遍历前先将节假日实例的所有键值对转为静态列表,完全加载所有节假日后再遍历,即可避免惰性加载带来的字典修改问题,优化后的代码如下:
import datetime, holidays import dateutil.easter as easter def to_date(date_string): return datetime.datetime.strptime(date_string,'%Y-%m-%d').date() def is_trading_holiday(date): us_holidays = holidays.UnitedStates(years=date.year) # 剔除哥伦布日和退伍军人节,美股上述节日正常交易 exclude_holidays = {"Columbus Day", "Columbus Day (Observed)", "Veterans Day", "Veterans Day (Observed)"} # 先转成静态items列表,触发全量加载后再遍历,避免迭代时修改原字典 custom_holidays = [ holiday_date for holiday_date, holiday_name in list(us_holidays.items()) if holiday_name not in exclude_holidays ] # 追加耶稣受难日,美股当日休市 custom_holidays.append(easter.easter(year=date.year) - datetime.timedelta(days=2)) return date in custom_holidays if __name__=="__main__": first_date = to_date('2020-01-03') second_date = to_date('2015-11-26') # 感恩节 third_date = to_date('2005-01-01') # 新年 fourth_date = to_date('2005-01-07') print(is_trading_holiday(first_date)) print(is_trading_holiday(second_date)) print(is_trading_holiday(third_date)) print(is_trading_holiday(fourth_date))
优化说明:将需要排除的节日存储结构从列表改为集合,in判断的时间复杂度从O(n)降至O(1),可提升大量日期校验时的性能。
内容的提问来源于stack exchange,提问作者Grant Moore
相关产品推荐
相关产品推荐

