折腾:
期间,需要去处理:
把a和b两个dict合并:
book_common.json
<code>{
"title": "Gitbook的书名",
"description": "gitbook书的描述",
"author": "Crifan Li <[email protected]>",
"language": "zh-hans",
"gitbook": "3.2.3",
"root": "./src",
"links": {
"sidebar": {
"主页": "https://www.crifan.com"
}
},
"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.com,使用<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.com/files/res/crifan_com/crifan_wechat_pay.jpg",
"alipay": "https://www.crifan.com/files/res/crifan_com/crifan_alipay_pay.jpg",
"title": "",
"button": "打赏",
"alipayText": "支付宝打赏给Crifan",
"wechatText": "微信打赏给Crifan"
},
"sitemap-general": {
"prefix": "https://book.crifan.com/gitbook/gitbook_name/website/"
},
"toolbar-button": {
"icon": "fa-file-pdf-o",
"label": "下载PDF",
"url": "http://book.crifan.com/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.com/gitbook/youdao_note_summary/website/"
},
"toolbar-button": {
"url": "http://book.crifan.com/books/youdao_note_summary/pdf/youdao_note_summary.pdf"
}
}
}
</code>希望合并后是:
<code>{
"title": "有道云笔记和云协作使用总结",
"description": "总结之前使用过有道云笔记和有道云协作的心得供参考",
"author": "Crifan Li <[email protected]>",
"language": "zh-hans",
"gitbook": "3.2.3",
"root": "./src",
"links": {
"sidebar": {
"主页": "https://www.crifan.com"
}
},
"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.com,使用<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.com/files/res/crifan_com/crifan_wechat_pay.jpg",
"alipay": "https://www.crifan.com/files/res/crifan_com/crifan_alipay_pay.jpg",
"title": "",
"button": "打赏",
"alipayText": "支付宝打赏给Crifan",
"wechatText": "微信打赏给Crifan"
},
"sitemap-general": {
"prefix": "https://book.crifan.com/gitbook/youdao_note_summary/website/"
},
"toolbar-button": {
"icon": "fa-file-pdf-o",
"label": "下载PDF",
"url": "http://book.crifan.com/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 <[email protected]>',
'description': '总结之前使用过有道云笔记和有道云协作的心得供参考',
'gitbook': '3.2.3',
'language': 'zh-hans',
'links': {
'sidebar': {
'主页': 'https://www.crifan.com'
}
},
'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.com/gitbook/youdao_note_summary/website/'
},
'toolbar-button': {
'url': 'http://book.crifan.com/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.com"
}
},
"author": "Crifan Li <[email protected]>",
"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.com/books/youdao_note_summary/pdf/youdao_note_summary.pdf",
"icon": "fa-file-pdf-o",
"label": "下载PDF"
},
"sitemap-general": {
"prefix": "https://book.crifan.com/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.com,使用<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.com/files/res/crifan_com/crifan_alipay_pay.jpg",
"title": "",
"alipayText": "支付宝打赏给Crifan",
"button": "打赏",
"wechatText": "微信打赏给Crifan",
"wechat": "https://www.crifan.com/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的递归的合并更新