Python:如何在单表达式中深层添加到字典?

8 投票
6 回答
1167 浏览
提问于 2025-04-15 12:41

我想知道,如何在一个表达式中,得到一个字典,其中一个键值对被添加到某个输入字典的子字典里?而且输入字典要保持不变。可以假设这个子字典是存在的,并且新的键值对在子字典中还不存在。

更新 2(下面会解释"SOsurvivalConditions"等的定义):

最简洁的方法是:

(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,
}

'firstCondition'在SOsurvivalConditions中现在有两个键值对。需要添加一个新的键值对,('synonym', '现代版的RTFM是:谷歌一下。'),并且结果应该在一个表达式中可用。

这个方法有效(虽然这里分成了几行,但实际上是一行):

{
    'moodImperative': SOsurvivalConditions['moodImperative'],
    'firstCondition' :
        dict(
               SOsurvivalConditions['firstCondition'],
               synonym = 'A modern form of RTFM is: 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。)

6 个回答

2

你是在寻找 dict.update 的用法吗?相关的文档可以在这里找到。

SOsurvivalConditions['firstCondition'].update({'synonym': 'A modern form of RTFM is: Google It.'})

我觉得这就是你想要的内容。

3

这里有一个满足你特殊要求的例子(在你描述的模糊范围内):

(SOsurvivalConditions['firstCondition'].setdefault('synonym', 'A modern form of RTM is: Google It.'), SOsurvivalConditions)[-1]

这个例子会修改最初的数据结构(而不是像@truppo的回答那样创建新的结构),而且它是一个表达式,会返回整个字典(而不是像@Evan的回答那样是一个语句,或者像@Seth的回答那样返回None)。

当然,很多不同的变体都是可能的(如果你希望新的条目覆盖一个已经存在的相同键'synonym'的条目,而不是保留这个已有的条目,你可以用__setitem__来代替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.')

根据在特殊情况下所需的确切行为,可能有几种变体。这个版本会在之前没有给定外键的条目时添加一个新的字典(只包含给定的内键值对);如果之前有这样的条目,它会尝试将其转换为字典(即使它原本是一个键值元组的列表),如果这样做不可行,就会抛出异常。一个更严格的版本(要求内条目已经存在并且是字典或类似字典的对象,如果不符合则抛出异常)可能会使用

inner = result[outerKey].copy()

作为主体中的第二个语句。

5

在编程中,有时候我们会遇到一些问题,像是代码运行不正常或者出现错误。这些问题可能是因为我们在写代码的时候,某些地方没有注意到,或者是对某些概念理解得不够清楚。

比如说,有些人可能在使用某个函数的时候,不太明白这个函数的具体作用,或者它需要什么样的输入。这就像是你在做菜时,可能会不清楚某种调料的用法,结果做出来的菜味道就不对了。

所以,遇到问题时,首先要仔细检查自己的代码,看看有没有拼写错误,或者是逻辑上有没有不合理的地方。然后,可以查阅一些资料,了解相关的知识,或者向其他人请教,获取更多的帮助。

总之,编程就像是解谜,需要耐心和细心,慢慢来,总能找到解决办法。

SOsurvivalConditions['firstCondition']['synonym'] = 'A modern form of RTM is: Google It.'

撰写回答