在 Python 中使用 None 值删除字典中键的正确方法

Posted

技术标签:

【中文标题】在 Python 中使用 None 值删除字典中键的正确方法【英文标题】:Proper way to remove keys in dictionary with None values in Python 【发布时间】:2016-02-21 04:42:30 【问题描述】:

在 Python 中从值 == None 的字典中删除键的正确方法是什么?

【问题讨论】:

您必须澄清您的意思,因为字典中的每个键都必须有一个值,即使该值是 ''0None k: v for k, v in original.items() if v is not None 【参考方案1】:

通常,您将通过过滤旧的dict 来创建一个新的dict。字典推导非常适合这种事情:

k: v for k, v in original.items() if v is not None

如果你必须更新原来的dict,你可以这样做...

filtered = k: v for k, v in original.items() if v is not None
original.clear()
original.update(filtered)

这可能是我能想到的最“干净”的就地删除它们的方法(在迭代时修改 dict 是不安全的)


在python2.x上使用original.iteritems()

【讨论】:

目前,此问题的其他两个答案似乎在从字典中删除时迭代字典。是你在最后一句中提到的吗?迭代 dict.keysdict.items? @RobertL -- 是的。如果您要在此过程中更改字典,则迭代 dict 总是不安全的。在 python2.x 上迭代 dict.keys()dict.items() 很好,但在 python3.x 上不安全。例如,请参阅***.com/a/6777632/748858。 感谢您使用 Python 3 语法进行更新。随着 Python 2 变老,这个答案变得越来越笨拙。也许是时候先提供 Python 3+ 的答案,并将遗留语法作为脚注。 @JasonR.Coombs -- 同意。我把这个改成默认为 python3.x —— 实际上这也可以在 python2.x 上工作,只是效率稍低。 如果您有嵌套字典,这似乎不起作用【参考方案2】:

如果您需要递归删除 None 值,最好使用这个:

def delete_none(_dict):
    """Delete None values recursively from all of the dictionaries"""
    for key, value in list(_dict.items()):
        if isinstance(value, dict):
            delete_none(value)
        elif value is None:
            del _dict[key]
        elif isinstance(value, list):
            for v_i in value:
                if isinstance(v_i, dict):
                    delete_none(v_i)

    return _dict

根据@dave-cz 的建议,添加了支持列表类型值的功能。

@mandragor 添加了额外的 if 语句以允许包含简单列表的字典。

如果您需要从字典、列表、元组、集合中删除所有 None 值,这也是一种解决方案:

def delete_none(_dict):
    """Delete None values recursively from all of the dictionaries, tuples, lists, sets"""
    if isinstance(_dict, dict):
        for key, value in list(_dict.items()):
            if isinstance(value, (list, dict, tuple, set)):
                _dict[key] = delete_none(value)
            elif value is None or key is None:
                del _dict[key]

    elif isinstance(_dict, (list, set, tuple)):
        _dict = type(_dict)(delete_none(item) for item in _dict if item is not None)

    return _dict


passed:
a = 
    "a": 12, "b": 34, "c": None,
    "k": "d": 34, "t": None, "m": ["k": 23, "t": None,[None, 1, 2, 3],1, 2, None], None: 123


returned:
a = 
    "a": 12, "b": 34, 
    "k": "d": 34, "m": ["k": 23, [1, 2, 3], 1, 2]

【讨论】:

您需要在_dict.items() 之前添加list() 以避免由于dict 在迭代期间更改大小而引发RunTimeError value 可以是具有 None 属性的字典列表,添加elif isinstance(value, list): for v_i in value: delete_none(v_i) 不需要返回_dict。这只会增加运行时间。 _dict 通过引用方法传递。您可以将要从中删除的字典的副本传递给此函数并获取结果。 如果您在顶层有一个数组,则缺少一个案例: mylist: [ 1, 2,3 ] @Mandragor 好点,谢谢,一开始就不能检查,比如: if not isinstance(_dict, dict): return _dict but your looks good【参考方案3】:

对于python 2.x

dict((k, v) for k, v in original.items() if v is not None)

【讨论】:

我不能代表反对者,但这里的答案有一个问题是,如果 bool(v) 评估为 Falsenot v 将评估为 True。例如,v == ''(空字符串)就是这种情况,这与 v == None 不同。 @Rob is not 不等于 isnot 的组合。它是一个完全独立的运算符来测试身份。请参阅 operator.is_notfor Python2 和 Python3。 @AminShahGilani 是的,答案已被编辑。它以前使用if not v 而不是if v is not None。我现在应该删除我的评论吗?【参考方案4】:

您还可以复制dict 以避免在更改原始dict 时对其进行迭代。

for k, v in dict(d).items():
    if v is None:
        del d[k]

但这对于较大的字典可能不是一个好主意。

【讨论】:

【参考方案5】:

如果你不想复制

for k,v  in list(foo.items()):
   if v is None:
      del foo[k]

【讨论】:

foo.pop(k) 更好,否则会失败 仅供参考,list 关键字创建键/值对的(浅)副本。 foo.pop(k) 如果没有键也会失败,更好,pop(k, None)【参考方案6】:

Python3递归版本

def drop_nones_inplace(d: dict) -> dict:
    """Recursively drop Nones in dict d in-place and return original dict"""
    dd = drop_nones(d)
    d.clear()
    d.update(dd)
    return d

def drop_nones(d: dict) -> dict:
    """Recursively drop Nones in dict d and return a new dict"""
    dd = 
    for k, v in d.items():
        if isinstance(v, dict):
            dd[k] = drop_nones(v)
        elif isinstance(v, (list, set, tuple)):
            # note: Nones in lists are not dropped
            # simply add "if vv is not None" at the end if required
            dd[k] = type(v)(drop_nones(vv) if isinstance(vv, dict) else vv 
                            for vv in v) 
        elif v is not None:
            dd[k] = v
    return dd

【讨论】:

【参考方案7】:

也许你会发现它很有用:

def clear_dict(d):
    if d is None:
        return None
    elif isinstance(d, list):
        return list(filter(lambda x: x is not None, map(clear_dict, d)))
    elif not isinstance(d, dict):
        return d
    else:
        r = dict(
                filter(lambda x: x[1] is not None,
                    map(lambda x: (x[0], clear_dict(x[1])),
                        d.items())))
        if not bool(r):
            return None
        return r

它会:

clear_dict(
    'a': 'b', 'c': 'd': ['e': None, 'f': 'g', 'h': None]
)

->

'a': 'b', 'c': 'd': ['f': 'g']

【讨论】:

以上是关于在 Python 中使用 None 值删除字典中键的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

Python:如何递归地从 NESTED 数据结构(列表和字典)中删除 None 值?

python字典中键值对的值为中文,打印成转义字符,怎么解决

Python中的字典

python字典的常用操作方法

字典中键重复时——pycharm和python IDLE打印的一个差别

Python 自动化运维1-字典