Python 可变对象以及何时复制它们

Python Mutable Objects and when to copy them

提问人:Stefan 提问时间:8/11/2017 更新时间:8/11/2017 访问量:469

问:

我有一个类似json的词典,其中包含其他词典和列表,如下所示:

        "A": {
            "attrib2": "bar", 
            "attrib1": "foo", 
            "B": "b", 
            "C": [
                "c1", 
                "c2"
            ], 
            "D": [
                {
                    "attrib3": "baz"
                }, 
                {
                    "attrib4": "muh"
                }
            ]
        }

每个值可以是列表(字典或值)、字典或不可变值(如“c1”或 5)。

现在我想搜索我通过获取它们所需的键引用的特定值([“A”, “B”] 将指向值 “b”)。由于给定的键路径中可能存在列表,因此我将返回所有找到的值。我的函数如下所示:

def getValues(inputDict, keyList):
    """
        works on dicts in json-like format as outputted by complexXmlElement2dict
    """
    values = list()
    if keyList:
        key = keyList.pop(0)
        try:
            currentValue = inputDict[key]
        except KeyError:
            logger.debug("could not find key {}".format(key))
            return list()

        if isinstance(currentValue, dict):
            additionalValues = getValues(copy.deepcopy(currentValue), list(keyList))  # copy list and dict!!
            values.extend(additionalValues)

        elif isinstance(currentValue, list):
            for subDict in currentValue:
                assert isinstance(subDict, dict)
                values.extend(getValues(copy.deepcopy(subDict), list(keyList)))  # copy list and dict!!
        else:
            values.append(currentValue)

    return list(values)

正如你所看到的,我对这里使用的可变对象有点偏执。我正在复制剩下的键列表以查找正确的值以及我每次使用的字典。我的函数按预期工作,但我认为我通过不必要地复制所有这些对象来产生大量开销。

我什么时候可以省略复制此示例中的字典和列表,为什么?试错是没有选择的,因为我没有所有可能的输入词典,也因为我想获得更好的理解。我应该补充一点,我已经阅读了很多关于python中可变对象的例子和解释,虽然我认为我理解了这个概念,但我感觉不够舒服,省略了我认为不必要的内容,因为其他人依赖于这段代码的正确性。

getValues(copy.deepcopy(currentValue), list(keyList))
getValues(copy.deepcopy(subDict), list(keyList)))
return list(values)

我正在使用 Python 2.7。

列表 字典 递归 可变

评论


答:

0赞 Mukesh Kumar 8/11/2017 #1

我找不到任何理由复制字典或列表。您没有更新其中任何一个。您只是从中提取数据。因此,只需在递归函数中传递引用即可。

评论

0赞 Stefan 8/11/2017
每次我深入一级时,我的 keyList 都会更新:key = keyList.pop(0),每次我找到与搜索模式匹配的值时,我的值列表都会更新。字典 currentValue 每次也指向大字典的不同部分。
0赞 Mukesh Kumar 8/11/2017
关于键列表,您可以每次传递相同的列表并传递索引以标识要处理的键。关于字典currentValue,它是否指向不同的大字典并不重要,如果你不更新它,你可以使用浅拷贝。无需深度复制。关于值列表,您始终在创建一个新列表,并将其附加到上一个列表中。您需要了解递归函数的概念。