Python:对字典进行深度附加?-一语道破
在单一表达式中如何获取词典 其中一个键值对已添加到子字典 在一些输入字典里?输入字典应保持不变。信息技术 可以假设子字典确实存在,并且新的键值对不在子字典中 更新2(有关“SOSurvival条件”等的定义,请参见下文): 最简洁的方式是:Python:对字典进行深度附加?-一语道破,python,Python,在单一表达式中如何获取词典 其中一个键值对已添加到子字典 在一些输入字典里?输入字典应保持不变。信息技术 可以假设子字典确实存在,并且新的键值对不在子字典中 更新2(有关“SOSurvival条件”等的定义,请参见下文): 最简洁的方式是: (SOsurvivalConditions['firstCondition'].setdefault('synonym', 'A modern form of RTFM is: Google It.'), SOsurvivalConditions)[-1]
(SOsurvivalConditions['firstCondition'].setdefault('synonym', 'A modern form of RTFM is: Google It.'), SOsurvivalConditions)[-1]
更新1:
这符合给定的要求,并且没有
修改输入字典的副作用:
dict((k,dict(v, synonym='A modern form of RTFM is: Google It.') if k == "firstCondition" else v) for k,v in SOsurvivalConditions.iteritems())
然而,更简洁(但仅限于陈述)的方式可以
使用辅助功能进行调整,例如:
import copy
def dictDeepAdd(inputDict, dictKey, newKey, newValue):
"""
Adds new key-value pair to a sub-dictionary and
returns a new version of inputDict.
dictKey is the key in inputDict for which a new
key-value pair is added.
Side-effect: none (does not change inputDict).
"""
toReturn = copy.deepcopy(inputDict)
toReturn[dictKey][newKey] = newValue
return toReturn
dictDeepAdd(
SOsurvivalConditions,
'firstCondition',
'synonym',
'A modern form of RTFM is: Google It.'
)
例如:
goodStyle = \
{
'answer': 'RTFM responses are not acceptable on Stack Overflow - Joel Spolsky has repeatedly said so in the Stack Overflow podcasts.',
'RTFM' : 'RTFM is, in the less offensive version, an abbreviation for Read The Fine Manual.',
}
SOsurvivalConditions = \
{
'moodImperative' : 'be happy',
'firstCondition' : goodStyle,
}
SOsurvivalConditions中的“firstCondition”现在有两个键值对。
一个新的键值对('synonym',RTFM的现代形式是:Google It.),
需要追加,并且结果应在单个表达式中可用
这是可行的(一行,但在这里分成几行):
并返回:
{'moodImperative': 'be happy',
'firstCondition':
{'answer': 'RTFM responses are not acceptable on Stack Overflow - Joel Spolsky has repeatedly said so in the Stack Overflow podcasts.',
'RTFM': 'RTFM is, in the less offensive version, an abbreviation for Read The Fine Manual.',
'synonym': 'A modern form of RTFM is: Google It.'
}
}
然而,这其中有很多冗余
表达式-重复所有键。“firstCondition”出现两次。还有别的吗
优雅的方式
(这里的数据结构的名称和内容是虚构的,但代表了我今天遇到的一个实际问题。Python版本:2.6.2。)。您正在寻找
dict.update
(文档)
我想,这就是你想要的。这是可行的,但并不漂亮,而且我认为你的lambda/oneliner/无论你想做什么,可能都做得太过分了:)
这里有一个确实符合您的特殊规格(在您指定的模糊范围内): 这确实会修改初始数据结构(而不是像@truppo的答案那样创建新的数据结构),并且也是一个返回整个字典的表达式(而不是像@Evan的答案那样是一个语句,或者像@Seth的答案那样不返回任何语句) 当然,有许多变体是可能的(例如,如果您希望新条目覆盖具有相同键“同义词”的现有条目,而不是保留任何此类现有条目,您可以使用
\uuuuuu setitem\uuuuu
而不是setdefault
,很难猜测在这种情况下您希望发生什么,因为您的初始规范非常模糊,而且(没有给出帮助消除歧义的“真实用例”上下文)
编辑:现在在注释中阐明了用例(不改变原始数据结构,确实需要一个表达式,但可以使用辅助函数),我建议如下:
def addSubEntry(mainDict, outerKey, innerKey, innerValue):
# copy inner and outer dicts to avoid altering initial data
result = dict(mainDict)
inner = dict(result.get(outerKey, {}))
inner[innerKey] = innerValue
result[outerKey] = inner
return result
作为所需的表达式,使用:
addSubEntry(SOsurvivalConditions, 'firstCondition', 'synonym', 'A modern form of RTM is: Google It.')
根据角落案例中所需的确切行为,可能会出现几种变体。如果以前没有具有给定外部键的条目,则此版本会添加一个新字典(仅具有给定的内部键值对);如果以前有这样的条目,则会尝试将其放入dict(即使它是键值元组列表),如果不可行,则引发异常。可能会使用更严格的版本(要求内部条目已经存在,并且是dict或类似dict的对象,而不是引发异常)
inner = result[outerKey].copy()
作为正文中的第二句话。Python 3是您的朋友:
{**SOsurvivalConditions, 'firstCondition': {**SOsurvivalConditions['firstCondition'], 'synonym': 'A modern form of RTFM is: Google It.'}}
一个单行表达式,返回带有附加子项的词典,而不修改原始词典或子词典。我相信这符合您的要求:
{k: dict(v, **{'synonym': 'A modern form of RTFM is: Google It.'}) if k == 'firstCondition' else v for k, v in SOsurvivalConditions.iteritems()}
这将生成一个新字典,该字典将在firstCondition
下获取原始字典的内部字典,并从中创建一个包含新项的新字典。需要注意的是,如果原始字典中有其他可变结构作为值,这将复制到新字典的引用上。这没有发生不过,您的问题似乎并非如此,您可以轻松地修改它,以生成这些可变结构的副本
这是一个肯定,这是有效的:
SOsurvivalConditions = {
'moodImperative' : 'be happy',
'firstCondition' : {
'answer': 'RTFM responses are not acceptable on Stack Overflow - Joel Spolsky has repeatedly said so in the Stack Overflow podcasts.',
'RTFM' : 'RTFM is, in the less offensive version, an abbreviation for Read The Fine Manual.',
},
}
target_dict = {
'moodImperative': 'be happy',
'firstCondition': {
'answer': 'RTFM responses are not acceptable on StackOverflow - Joel Spolsky has repeatedly said so in the Stack Overflow podcasts.',
'RTFM': 'RTFM is, in the less offensive version, an abbreviation for Read The Fine Manual.',
'synonym': 'A modern form of RTFM is: Google It.'
},
}
new_dict = {k: dict(v, **{'synonym': 'A modern form of RTFM is: Google It.'}) if k == 'firstCondition' else v for k, v in SOsurvivalConditions.iteritems()}
assert(SOsurvivalConditions['firstCondition'].get('synonym') is None) # asserts original dict didn't change
assert(new_dict == target_dict) # asserts target dictionary is produced
这将改变SOsurvivalConditions。但它是一个将返回值的表达式吗?例如,我可以用上面的行调用一个函数,并期望该函数通过(更新的)dictionary?不,它不会返回值。是否要求它在单行中返回dictionary?如果是,请您进一步解释一下发生的情况的上下文?它用于我要传递的Django URL.py文件中(额外)从URL中捕获信息以用于模板HTML文件。也许使用帮助函数而不是单个表达式是更简单的解决方案。@Peter,我同意帮助函数的想法,尤其是,既然您在注释中指定不想修改原始数据,只需返回修改过的副本,请参阅我刚刚编辑的a鉴于这些明确的规范,请回答我建议的细节。我看不出“单行”约束如何可能“代表一个真正的问题”。SOsurvivalConditions中的值是异构类型的——一个字符串,一个dict——以及所提供的所有解决方案(您和其他人)如果试图向字符串中添加新条目,则会爆炸;当然,在面对此类可能的错误时,需要额外的一两行代码才能保持稳健。而且,您永远不会澄清是否要更改原始结构,或构建全新的结构——在实际问题中,这种小细节通常很重要!)我想转换输入(不改变它),并将结果传递给函数。那么,一个helper函数而不是一个表达式会是首选的解决方案吗?我确实会建议一个helper函数,我将编辑我的答案以建议一个。它返回None,这不是他说的想要的;-)他的问题完全不清楚我很乐意帮忙;-)。让我编辑我的答案,建议一个好的“助手函数”。如何更改方法以接受可变数量的内键,使其更通用
addSubEntry(SOsurvivalConditions, 'firstCondition', 'synonym', 'A modern form of RTM is: Google It.')
inner = result[outerKey].copy()
{**SOsurvivalConditions, 'firstCondition': {**SOsurvivalConditions['firstCondition'], 'synonym': 'A modern form of RTFM is: Google It.'}}
{k: dict(v, **{'synonym': 'A modern form of RTFM is: Google It.'}) if k == 'firstCondition' else v for k, v in SOsurvivalConditions.iteritems()}
SOsurvivalConditions = {
'moodImperative' : 'be happy',
'firstCondition' : {
'answer': 'RTFM responses are not acceptable on Stack Overflow - Joel Spolsky has repeatedly said so in the Stack Overflow podcasts.',
'RTFM' : 'RTFM is, in the less offensive version, an abbreviation for Read The Fine Manual.',
},
}
target_dict = {
'moodImperative': 'be happy',
'firstCondition': {
'answer': 'RTFM responses are not acceptable on StackOverflow - Joel Spolsky has repeatedly said so in the Stack Overflow podcasts.',
'RTFM': 'RTFM is, in the less offensive version, an abbreviation for Read The Fine Manual.',
'synonym': 'A modern form of RTFM is: Google It.'
},
}
new_dict = {k: dict(v, **{'synonym': 'A modern form of RTFM is: Google It.'}) if k == 'firstCondition' else v for k, v in SOsurvivalConditions.iteritems()}
assert(SOsurvivalConditions['firstCondition'].get('synonym') is None) # asserts original dict didn't change
assert(new_dict == target_dict) # asserts target dictionary is produced