Jinja2渲染设备配置触发RuntimeError:字典迭代期间大小改变问题
问题根因
你遇到的RuntimeError: dictionary changed size during iteration错误核心诱因是**bgpProto字段是defaultdict(bgpGroup)类型**:
defaultdict的特性是访问不存在的键时,会自动调用传入的工厂函数(这里是bgpGroup())创建默认实例,并把这个键值对插入字典。你的bgpGroup初始化时grpName默认值就是default,所以一旦模板中访问了bgpProto中不存在的键,就会自动插入一个key为default、grpName为default的bgpGroup实例,导致迭代字典时大小发生变化触发报错。
而Vendor2的模板没有触发问题,是因为Vendor2模板中没有访问bgpProto不存在的键的逻辑,不会触发defaultdict自动插入值。你用copy.copy做浅拷贝无效的原因是浅拷贝只会复制外层对象,内层的bgpProto defaultdict还是和原对象指向同一块内存地址,模板里的操作依然会修改原字典。
解决方案
你可以按优先级选以下任意一种方案修复:
- 优先排查Vendor1模板第71行附近的代码,确认是否有拼写错误、或者误访问
bgpProto['default']的逻辑,把错误的键访问逻辑删掉即可从根源解决问题。 - 如果你不需要defaultdict自动创建实例的特性,直接把
bgpProto的类型从defaultdict(bgpGroup)改成普通dict,这样访问不存在的键会直接抛出KeyError,可以快速定位到错误的访问位置,不会偷偷插入默认值。 - 不改模板的前提下,修改Jinja2迭代逻辑,先把字典转成静态列表再迭代,避免迭代过程中字典变化影响:
{%- for tBgpGrp in config.vrfs[tvrf].bgpProto.items() | list %} - 如果你需要保留defaultdict的特性,把渲染前的浅拷贝改成深拷贝,避免模板操作修改原对象:
import copy lerConfig = lerTemplate.render(config=copy.deepcopy(config.lerDevList[tLer]))
内容的提问来源于stack exchange,提问作者nk2soflow
相关产品推荐
相关产品推荐

