折腾:
期间,需要去处理:
把a和b两个dict合并:
book_common.json
<code>{
  "title": "Gitbook的书名",
  "description": "gitbook书的描述",
  "author": "Crifan Li <admin@crifan.org>",
  "language": "zh-hans",
  "gitbook": "3.2.3",
  "root": "./src",
  "links": {
    "sidebar": {
      "主页": "https://www.crifan.org"
    }
  },
  "plugins": [
    "theme-comscore",
    "-lunr",
    "-search",
    "search-plus",
    "disqus",
    "-highlight",
    "prism",
    "prism-themes",
    "github-buttons",
    "splitter",
    "-sharing",
    "sharing-plus",
    "tbfed-pagefooter",
    "expandable-chapters-small",
    "ga",
    "donate",
    "sitemap-general",
    "copy-code-button",
    "-alerts",
    "-bootstrap-callout",
    "callouts",
    "toolbar-button"
  ],
  "pluginsConfig": {
    "callouts": {
      "showTypeInHeader": false
        },
    "theme-default": {
        "showLevel": true
    },
    "disqus": {
      "shortName": "crifan"
    },
    "prism": {
      "css": [
        "prism-themes/themes/prism-atom-dark.css"
      ]
    },
    "github-buttons": {
      "buttons": [
        {
          "user": "crifan",
          "repo": "gitbook_name",
          "type": "star",
          "count": true,
          "size": "small"
        }, {
          "user": "crifan",
          "type": "follow",
          "width": "120",
          "count": false,
          "size": "small"
        }
      ]
    },
    "sharing": {
      "douban": false,
      "facebook": true,
      "google": false,
      "hatenaBookmark": false,
      "instapaper": false,
      "line": false,
      "linkedin": false,
      "messenger": false,
      "pocket": false,
      "qq": true,
      "qzone": false,
      "stumbleupon": false,
      "twitter": true,
      "viber": false,
      "vk": false,
      "weibo": true,
      "whatsapp": false,
      "all": [
        "douban",
        "facebook",
        "google",
        "instapaper",
        "line",
        "linkedin",
        "messenger",
        "pocket",
        "qq",
        "qzone",
        "stumbleupon",
        "twitter",
        "viber",
        "vk",
        "weibo",
        "whatsapp"
      ]
    },
    "tbfed-pagefooter": {
      "copyright": "crifan.org,使用<a href='https://creativecommons.org/licenses/by-sa/4.0/deed.zh'>知识署名-相同方式共享4.0协议</a>发布",
      "modify_label": "该文件修订时间:",
      "modify_format": "YYYY-MM-DD HH:mm:ss"
    },
    "ga": {
      "token": "UA-28297199-1"
    },
    "donate": {
      "wechat": "https://www.crifan.org/files/res/crifan_com/crifan_wechat_pay.jpg",
      "alipay": "https://www.crifan.org/files/res/crifan_com/crifan_alipay_pay.jpg",
      "title": "",
      "button": "打赏",
      "alipayText": "支付宝打赏给Crifan",
      "wechatText": "微信打赏给Crifan"
    },
    "sitemap-general": {
      "prefix": "https://book.crifan.org/gitbook/gitbook_name/website/"
    },
    "toolbar-button": {
      "icon": "fa-file-pdf-o",
      "label": "下载PDF",
      "url": "http://book.crifan.org/books/gitbook_name/pdf/gitbook_name.pdf"
    }
  }
}
</code>book_current.json
<code>{
  "title": "有道云笔记和云协作使用总结",
  "description": "总结之前使用过有道云笔记和有道云协作的心得供参考",
  "pluginsConfig": {
    "github-buttons": {
      "buttons": [
        {
          "repo": "youdao_note_summary"
        }
      ]
    },
    "sitemap-general": {
      "prefix": "https://book.crifan.org/gitbook/youdao_note_summary/website/"
    },
    "toolbar-button": {
      "url": "http://book.crifan.org/books/youdao_note_summary/pdf/youdao_note_summary.pdf"
    }
  }
}
</code>希望合并后是:
<code>{
  "title": "有道云笔记和云协作使用总结",
  "description": "总结之前使用过有道云笔记和有道云协作的心得供参考",
  "author": "Crifan Li <admin@crifan.org>",
  "language": "zh-hans",
  "gitbook": "3.2.3",
  "root": "./src",
  "links": {
    "sidebar": {
      "主页": "https://www.crifan.org"
    }
  },
  "plugins": [
    "theme-comscore",
    "-lunr",
    "-search",
    "search-plus",
    "disqus",
    "-highlight",
    "prism",
    "prism-themes",
    "github-buttons",
    "splitter",
    "-sharing",
    "sharing-plus",
    "tbfed-pagefooter",
    "expandable-chapters-small",
    "ga",
    "donate",
    "sitemap-general",
    "copy-code-button",
    "-alerts",
    "-bootstrap-callout",
    "callouts",
    "toolbar-button"
  ],
  "pluginsConfig": {
    "callouts": {
      "showTypeInHeader": false
        },
    "theme-default": {
        "showLevel": true
    },
    "disqus": {
      "shortName": "crifan"
    },
    "prism": {
      "css": [
        "prism-themes/themes/prism-atom-dark.css"
      ]
    },
    "github-buttons": {
      "buttons": [
        {
          "user": "crifan",
          "repo": "youdao_note_summary",
          "type": "star",
          "count": true,
          "size": "small"
        }, {
          "user": "crifan",
          "type": "follow",
          "width": "120",
          "count": false,
          "size": "small"
        }
      ]
    },
    "sharing": {
      "douban": false,
      "facebook": true,
      "google": false,
      "hatenaBookmark": false,
      "instapaper": false,
      "line": false,
      "linkedin": false,
      "messenger": false,
      "pocket": false,
      "qq": true,
      "qzone": false,
      "stumbleupon": false,
      "twitter": true,
      "viber": false,
      "vk": false,
      "weibo": true,
      "whatsapp": false,
      "all": [
        "douban",
        "facebook",
        "google",
        "instapaper",
        "line",
        "linkedin",
        "messenger",
        "pocket",
        "qq",
        "qzone",
        "stumbleupon",
        "twitter",
        "viber",
        "vk",
        "weibo",
        "whatsapp"
      ]
    },
    "tbfed-pagefooter": {
      "copyright": "crifan.org,使用<a href='https://creativecommons.org/licenses/by-sa/4.0/deed.zh'>知识署名-相同方式共享4.0协议</a>发布",
      "modify_label": "该文件修订时间:",
      "modify_format": "YYYY-MM-DD HH:mm:ss"
    },
    "ga": {
      "token": "UA-28297199-1"
    },
    "donate": {
      "wechat": "https://www.crifan.org/files/res/crifan_com/crifan_wechat_pay.jpg",
      "alipay": "https://www.crifan.org/files/res/crifan_com/crifan_alipay_pay.jpg",
      "title": "",
      "button": "打赏",
      "alipayText": "支付宝打赏给Crifan",
      "wechatText": "微信打赏给Crifan"
    },
    "sitemap-general": {
      "prefix": "https://book.crifan.org/gitbook/youdao_note_summary/website/"
    },
    "toolbar-button": {
      "icon": "fa-file-pdf-o",
      "label": "下载PDF",
      "url": "http://book.crifan.org/books/youdao_note_summary/pdf/youdao_note_summary.pdf"
    }
  }
}
</code>python json merge
python dict merge
How to merge two json string in Python? – Stack Overflow
python – How to merge two dictionaries in a single expression? – Stack Overflow
去试试效果
结果:
<code>bookJson = {**templateJson, **currentJson}
pprint(bookJson)
</code>合并后是:
<code>{
  'root': './src',
  'title': '有道云笔记和云协作使用总结',
  'author': 'Crifan Li <admin@crifan.org>',
  'description': '总结之前使用过有道云笔记和有道云协作的心得供参考',
  'gitbook': '3.2.3',
  'language': 'zh-hans',
  'links': {
    'sidebar': {
      '主页': 'https://www.crifan.org'
    }
  },
  'plugins': [
    'theme-comscore',
    '-lunr',
    '-search',
    'search-plus',
    'disqus',
    '-highlight',
    'prism',
    'prism-themes',
    'github-buttons',
    'splitter',
    '-sharing',
    'sharing-plus',
    'tbfed-pagefooter',
    'expandable-chapters-small',
    'ga',
    'donate',
    'sitemap-general',
    'copy-code-button',
    '-alerts',
    '-bootstrap-callout',
    'callouts',
    'toolbar-button'
  ],
  'pluginsConfig': {
    'github-buttons': {
      'buttons': [{
        'repo': 'youdao_note_summary'
      }]
    },
    'sitemap-general': {
      'prefix': 'https://book.crifan.org/gitbook/youdao_note_summary/website/'
    },
    'toolbar-button': {
      'url': 'http://book.crifan.org/books/youdao_note_summary/pdf/youdao_note_summary.pdf'
    }
  }
}
</code>其中基本的字段,比如title和description,是合并update了的
但是pluginsConfig的部分,只有后者,没有前面的值了。
试试别的方案
<code>bookJson = templateJson.copy() bookJson.update(currentJson) pprint(bookJson) </code>
问题依旧:

<code>bookJson = dict(templateJson, **currentJson) </code>
问题依旧。
<code>from collections import ChainMap
bookJson = ChainMap({}, currentJson, templateJson)
print("type(bookJson)=", type(bookJson))
</code>
问题依旧。
<code>def recursiveUpdateDict(original, update): """ Recursively update a dict. Subdict's won't be overwritten but also updated. """ for key, value in original.iteritems(): if key not in update: update[key] = value elif isinstance(value, dict): recursiveUpdateDict(value, update[key]) return update bookJson = recursiveUpdateDict(templateJson, currentJson) </code>
但是出错:
<code> for key, value in original.iteritems(): AttributeError: 'dict' object has no attribute 'iteritems' </code>
AttributeError: ‘dict’ object has no attribute ‘iteritems’
AttributeError: ‘dict’ object has no attribute ‘iteritems’ – CSDN博客
Python3下AttributeError: ‘dict’ object has no attribute ‘iteritems’的问题分析 – CSDN博客
改为:
<code>def recursiveUpdateDict(original, update): """ Recursively update a dict. Subdict's won't be overwritten but also updated. """ # for key, value in original.iteritems(): for key, value in original.items(): if key not in update: update[key] = value elif isinstance(value, dict): recursiveUpdateDict(value, update[key]) return update bookJson = recursiveUpdateDict(templateJson, currentJson) </code>
结果:
好像是可以的。
再去升级代码,支持Python2和Python3:

经过优化后,完整代码是:
<code>from pprint import pprint
import sys
templateJson = {}
currentJson = {}
。。。
def recursiveMergeDict(originalDict, toMergeDict):
    """
    Recursively update a dict.
    Sub dict's won't be overwritten but also updated.
    """
    originalDictItems = None
    if (sys.version_info[0] == 2): # is python 2
      originalDictItems = originalDict.iteritems()
    else:
      originalDictItems = originalDict.items()
    
    mergedDict = toMergeDict.copy()
    for key, value in originalDictItems:
      if key not in mergedDict:
          mergedDict[key] = value
      elif isinstance(value, dict):
          recursiveMergeDict(value, mergedDict[key])
    return mergedDict
bookJson = recursiveMergeDict(templateJson, currentJson)
pprint("-"*80)
pprint(bookJson)
pprint("-"*80)
pprint(currentJson)
</code>效果:

可见,merge后,a和b中的b,也是没有被修改的,而是返回a和b合并后的结果c的。
【后记1】
后来发现上述写法有问题:
传入a和b,结果b会被修改
而上面的写法,没法起到递归的效果
【后记2】
折腾了:
【已解决】python中把dict的json输出到文件且带缩进和不要unicode的\uxxxx
后,输出的结果是:
<code>{
  "description": "总结之前使用过有道云笔记和有道云协作的心得供参考", 
  "links": {
    "sidebar": {
      "主页": "https://www.crifan.org"
    }
  }, 
  "author": "Crifan Li <admin@crifan.org>", 
  "title": "有道云笔记和云协作使用总结", 
  "gitbook": "3.2.3", 
  "language": "zh-hans", 
  "plugins": [
    "theme-comscore", 
    "-lunr", 
    "-search", 
    "search-plus", 
    "disqus", 
    "-highlight", 
    "prism", 
    "prism-themes", 
    "github-buttons", 
    "splitter", 
    "-sharing", 
    "sharing-plus", 
    "tbfed-pagefooter", 
    "expandable-chapters-small", 
    "ga", 
    "donate", 
    "sitemap-general", 
    "copy-code-button", 
    "-alerts", 
    "-bootstrap-callout", 
    "callouts", 
    "toolbar-button"
  ], 
  "pluginsConfig": {
    "toolbar-button": {
      "url": "http://book.crifan.org/books/youdao_note_summary/pdf/youdao_note_summary.pdf", 
      "icon": "fa-file-pdf-o", 
      "label": "下载PDF"
    }, 
    "sitemap-general": {
      "prefix": "https://book.crifan.org/gitbook/youdao_note_summary/website/"
    }, 
    "sharing": {
      "qq": true, 
      "douban": false, 
      "all": [
        "douban", 
        "facebook", 
        "google", 
        "instapaper", 
        "line", 
        "linkedin", 
        "messenger", 
        "pocket", 
        "qq", 
        "qzone", 
        "stumbleupon", 
        "twitter", 
        "viber", 
        "vk", 
        "weibo", 
        "whatsapp"
      ], 
      "google": false, 
      "stumbleupon": false, 
      "hatenaBookmark": false, 
      "twitter": true, 
      "vk": false, 
      "linkedin": false, 
      "instapaper": false, 
      "pocket": false, 
      "weibo": true, 
      "viber": false, 
      "facebook": true, 
      "qzone": false, 
      "messenger": false, 
      "line": false, 
      "whatsapp": false
    }, 
    "tbfed-pagefooter": {
      "modify_format": "YYYY-MM-DD HH:mm:ss", 
      "modify_label": "该文件修订时间:", 
      "copyright": "crifan.org,使用<a href='https://creativecommons.org/licenses/by-sa/4.0/deed.zh'>知识署名-相同方式共享4.0协议</a>发布"
    }, 
    "github-buttons": {
      "buttons": [
        {
          "repo": "youdao_note_summary"
        }
      ]
    }, 
    "disqus": {
      "shortName": "crifan"
    }, 
    "prism": {
      "css": [
        "prism-themes/themes/prism-atom-dark.css"
      ]
    }, 
    "ga": {
      "token": "UA-28297199-1"
    }, 
    "theme-default": {
      "showLevel": true
    }, 
    "donate": {
      "alipay": "https://www.crifan.org/files/res/crifan_com/crifan_alipay_pay.jpg", 
      "title": "", 
      "alipayText": "支付宝打赏给Crifan", 
      "button": "打赏", 
      "wechatText": "微信打赏给Crifan", 
      "wechat": "https://www.crifan.org/files/res/crifan_com/crifan_wechat_pay.jpg"
    }, 
    "callouts": {
      "showTypeInHeader": false
    }
  }, 
  "root": "./src"
}
</code>其中大部分的json的内容,是合并对了。
但是部分内容,并没有合并更新:
对于:
<code>    "github-buttons": {
      "buttons": [
        {
          "user": "crifan",
          "repo": "gitbook_name",
          "type": "star",
          "count": true,
          "size": "small"
        }, {
          "user": "crifan",
          "type": "follow",
          "width": "120",
          "count": false,
          "size": "small"
        }
      ]
    },
</code>和:
<code>    "github-buttons": {
      "buttons": [
        {
          "repo": "youdao_note_summary"
        }
      ]
    },
</code>结果是:
<code>    "github-buttons": {
      "buttons": [
        {
          "repo": "youdao_note_summary"
        }
      ]
    }, 
</code>其实希望的是
<code>    "github-buttons": {
      "buttons": [
        {
          "user": "crifan",
          "repo": "youdao_note_summary",
          "type": "star",
          "count": true,
          "size": "small"
        }, {
          "user": "crifan",
          "type": "follow",
          "width": "120",
          "count": false,
          "size": "small"
        }
      ]
    },
</code>所以前面的合并算法还是有问题。
去优化
【总结】
最后用代码:
<code>def recursiveMergeDict(aDict, bDict):
    """
    Recursively merge dict a to b, return merged dict b
    Note: Sub dict's won't be overwritten but also updated/merged
    """
    aDictItems = None
    if (sys.version_info[0] == 2): # is python 2
      aDictItems = aDict.iteritems()
    else: # is python 3
      aDictItems = aDict.items()
    for aKey, aValue in aDictItems:
      print("------ [%s]=%s" % (aKey, aValue))
      if aKey not in bDict:
        bDict[aKey] = aValue
      else:
        bValue = bDict[aKey]
        print("aValue=%s" % aValue)
        print("bValue=%s" % bValue)
        if isinstance(aValue, dict):
          recursiveMergeDict(aValue, bValue)
        elif isinstance(aValue, list):
          aValueListLen = len(aValue)
          bValueListLen = len(bValue)
          bValueListMaxIdx = bValueListLen - 1
          for aListIdx in range(aValueListLen):
            print("---[%d]" % aListIdx)
            aListItem = aValue[aListIdx]
            print("aListItem=%s" % aListItem)
            if aListIdx <= bValueListMaxIdx:
              bListItem = bValue[aListIdx]
              print("bListItem=%s" % bListItem)
              recursiveMergeDict(aListItem, bListItem)
            else:
              # recursiveMergeDict(aListItem, aListItem)
              print("bDict=%s" % bDict)
              print("aKey=%s" % aKey)
              print("aListItem=%s" % aListItem)
              bDict[aKey].append(aListItem)
    return bDict
bookJson = recursiveMergeDict(templateJson, copy.deepcopy(currentJson))
pprint("-a"*40)
pprint(templateJson)
pprint("-b"*40)
pprint(currentJson)
pprint("-c"*40)
pprint(bookJson)
</code>输出:
<code>'-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a-a'
{u'pluginsConfig': {u'github-buttons': {u'buttons': [{u'count': True,
                                                      u'repo': u'gitbook_name',
                                                      u'size': u'small',
                                                      u'type': u'star',
                                                      u'user': u'crifan'},
                                                     {u'count': False,
                                                      u'size': u'small',
                                                      u'type': u'follow',
                                                      u'user': u'crifan',
                                                      u'width': u'120'},
                                                     {u'key1': u'string1',
                                                      u'key2': 999,
                                                      u'key3': True}]}}}
'-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b-b'
{u'pluginsConfig': {u'github-buttons': {u'buttons': [{u'repo': u'youdao_note_summary'}]}}}
'-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c-c'
{u'pluginsConfig': {u'github-buttons': {u'buttons': [{u'count': True,
                                                      u'repo': u'youdao_note_summary',
                                                      u'size': u'small',
                                                      u'type': u'star',
                                                      u'user': u'crifan'},
                                                     {u'count': False,
                                                      u'size': u'small',
                                                      u'type': u'follow',
                                                      u'user': u'crifan',
                                                      u'width': u'120'},
                                                     {u'key1': u'string1',
                                                      u'key2': 999,
                                                      u'key3': True}]}}}
</code>实现了希望看到的效果:
合并a和b的dict
- 如果包含子dict,则递归去合并 
- 如果包含list,则针对每个item去合并 
- 如果a的list比b多,则保留a多出的部分 
转载请注明:在路上 » 【已解决】Python中实现dict的递归的合并更新