Python:对字典进行深度附加?-一语道破

Python:对字典进行深度附加?-一语道破,python,Python,在单一表达式中如何获取词典 其中一个键值对已添加到子字典 在一些输入字典里?输入字典应保持不变。信息技术 可以假设子字典确实存在,并且新的键值对不在子字典中 更新2(有关“SOSurvival条件”等的定义,请参见下文): 最简洁的方式是: (SOsurvivalConditions['firstCondition'].setdefault('synonym', 'A modern form of RTFM is: Google It.'), SOsurvivalConditions)[-1]

单一表达式中如何获取词典 其中一个键值对已添加到子字典 在一些输入字典里?输入字典应保持不变。信息技术 可以假设子字典确实存在,并且新的键值对不在子字典中

更新2(有关“SOSurvival条件”等的定义,请参见下文):

最简洁的方式是:

(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