代码片段-复杂结构字典merge
两个字典递归merge, 并打印出 merge过程中, 简单数据类型(非字典, 列表)被替换的节点
def dict_merge(dct, merge_dct, cur_section, error_list, error_prefix=""):
"""Recursive dict merge. Inspired by :meth:``dict.update()``, instead of
updating only top-level keys, dict_merge recurses down into dicts nested
to an arbitrary depth, updating keys. The ``merge_dct`` is merged into
``dct``.
:param dct: dict onto which the merge is executed
:param merge_dct: dct merged into dct
:param cur_section: 记录当前比较到的节点位置
:param error_list: merge 过程中的冲突
:param error_prefix: 错误信息的前缀
:return: None
"""
for k, v in merge_dct.iteritems():
if k in dct:
if isinstance(dct[k], dict) and isinstance(merge_dct[k], dict):
if cur_section:
cur_section.append(k)
else:
cur_section = [k]
dict_merge(dct[k], merge_dct[k], cur_section, error_list, error_prefix=error_prefix)
elif isinstance(dct[k], (list, tuple)) and isinstance(v, (list, tuple)):
if cur_section:
cur_section.append(k)
else:
cur_section = [k]
temp_list = cur_section[:]
temp_list.reverse()
lasted_index = len(temp_list) - temp_list.index(k)
for index, arr_item in enumerate(dct[k]):
if isinstance(arr_item, dict) and isinstance(v[index], dict):
if cur_section:
cur_section.append(str(index))
else:
cur_section = [str(index)]
dict_merge(arr_item, v[index], cur_section, error_list, error_prefix=error_prefix)
cur_section = cur_section[:lasted_index]
elif dct[k] != v:
print("warninig...", k, dct[k], v)
err_data = {
"error_prefix": error_prefix,
"section": ".".join(cur_section) + "." + k,
# "section": [k],
"origin_data": dct[k],
"merge_data": merge_dct[k]
}
error_list.append(err_data)
dct[k] = merge_dct[k]
else:
dct[k] = merge_dct[k]
if k in cur_section:
temp_list = cur_section[:]
temp_list.reverse()
lasted_index = len(temp_list) - temp_list.index(k) - 1 # 需要把当前这层也去掉
cur_section = cur_section[:lasted_index]
def run_dict_merge():
import pprint
dct = {'interstitial_ad_plan': None,
'reward_ad_plan': None,
'promotion_plan': None,
'Module': {'Commands': {'OpenRookie': {'CornerDict': {'Priority': 500,
'resourceName': 'RokieButton',
'ChannelName': 'Channel_0'},
'showCount': 1000,
'Interval': 0,
'Priority': 800,
'eventDict': {'event': 'OpenRookie'},
'Conditions': [{'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'Description': 'GeneralEvent',
'ConditionContent': {'IsRookieOnlyBuyOnce': True,
'FirstCoolDownGlobalSpinCountInterval': 2000,
'TriggerMoment': 'SpinEnd',
'PopUpSuspend': True,
'SwitchOn': True},
'ConditionName': 'AfterSpinClicked'},
{'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'Description': 'RookieOfferEvent',
'ConditionContent': {'IsRookieOnlyBuyOnce': True,
'Probality': '1,3',
'TriggerMoment': 'BackToLobby',
'SwitchOn': True},
'ConditionName': 'BackToLobby'},
{'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'Description': 'RookieOfferEvent',
'ConditionContent': {'IsRookieOnlyBuyOnce': True,
'TriggerMoment': 'EnterLobby'},
'ConditionName': 'LobbyOpenRookie'},
{'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'Description': 'RookieOfferEvent',
'ConditionContent': {'IsRookieOnlyBuyOnce': True,
'Probality': '2,2',
'TriggerMoment': 'CloseShop'},
'ConditionName': 'CloseShopRookie'},
{'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'Description': 'RookieOfferEvent',
'ConditionContent': {'IsRookieOnlyBuyOnce': True,
'Probality': '3,10',
'TriggerMoment': 'CloseBigWin'},
'ConditionName': 'MachineBigWinRookie'},
{'ConditionName': 'MachineOutofCoinsRookie',
'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'ConditionContent': {'IsRookieOnlyBuyOnce': True,
'Probality': '4,4',
'TriggerMoment': 'CloseOutOfCoins'},
'Desacription': 'RookieOfferEvent'}],
'type': 'eventCmd'}}},
'store_plan': None}
merge_dct = {'interstitial_ad_plan': None,
'reward_ad_plan': None,
'promotion_plan': None,
'Module': {'Commands': {'OpenRookie': {'eventDict': {'event': 'OpenRookie'},
'showCount': 1200,
'Interval': 0,
'Priority': 1800,
'CornerDict': {'Priority': 5600,
'resourceName': 'RokieButton',
'ChannelName': 'Channel_0'},
'type': 'eventCmd',
'Conditions': [{'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'Description': 'GeneralEvent',
'ConditionContent': {
'IsRookieOnlyBuyOnce': True,
'FirstCoolDownGlobalSpinCountInterval': 2000,
'TriggerMoment': 'SpinEnd',
'PopUpSuspend': False,
'SwitchOn': True},
'ConditionName': 'AfterSpinClicked'},
{'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'Description': 'RookieOfferEvent',
'ConditionContent': {
'IsRookieOnlyBuyOnce': True,
'Probality': '1,3',
'TriggerMoment': 'BackToLobby',
'SwitchOn': True},
'ConditionName': 'BackToLobby'},
{'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'Description': 'RookieOfferEvent',
'ConditionContent': {
'IsRookieOnlyBuyOnce': True,
'TriggerMoment': 'EnterLobby'},
'ConditionName': 'LobbyOpenRookie'},
{'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'Description': 'RookieOfferEvent',
'ConditionContent': {
'IsRookieOnlyBuyOnce': True,
'Probality': '2,3',
'TriggerMoment': 'CloseShop'},
'ConditionName': 'CloseShopRookie'},
{'ConditionType': 'EventCondition',
'R': 'OpenRookie',
'Description': 'RookieOfferEvent',
'ConditionContent': {
'IsRookieOnlyBuyOnce': True,
'Probality': '3,10',
'TriggerMoment': 'CloseBigWin'},
'ConditionName': 'MachineBigWinRookie'},
{'R': 'OpenRookie',
'ConditionType': 'EventCondition',
'Desacription': 'RookieOfferEvent',
'ConditionContent': {
'IsRookieOnlyBuyOnce': True,
'Probality': '4,4',
'TriggerMoment': 'CloseOutOfCoins'},
'ConditionName': 'MachineOutofCoinsRookie'}]}}},
'store_plan': None}
cur_section = []
error_list = []
dict_merge(dct, merge_dct, cur_section, error_list)
print(cur_section)
pprint.pprint(error_list)
执行结果
('warninig...', 'Priority', 500, 5600)
('warninig...', 'showCount', 1000, 1200)
('warninig...', 'Priority', 800, 1800)
('warninig...', 'PopUpSuspend', True, False)
('warninig...', 'Probality', '2,2', '2,3')
[] # cur_section 已经是空的了
[{'error_prefix': '',
'merge_data': 5600,
'origin_data': 500,
'section': 'Module.Commands.OpenRookie.CornerDict.Priority'},
{'error_prefix': '',
'merge_data': 1200,
'origin_data': 1000,
'section': 'Module.Commands.OpenRookie.showCount'},
{'error_prefix': '',
'merge_data': 1800,
'origin_data': 800,
'section': 'Module.Commands.OpenRookie.Priority'},
{'error_prefix': '',
'merge_data': False,
'origin_data': True,
'section': 'Module.Commands.OpenRookie.Conditions.0.ConditionContent.PopUpSuspend'},
{'error_prefix': '',
'merge_data': '2,3',
'origin_data': '2,2',
'section': 'Module.Commands.OpenRookie.Conditions.3.ConditionContent.Probality'}]

浙公网安备 33010602011771号