首先,我认为你的代码可以工作,但不能不优雅的。没有直接的理由不使用您提供的代码。
不过,有一些事情可以做得更好:
比较类型
您的代码包含以下行:
if type(dict_foo[field]) == dict:
这绝对是可以改进的。一般来说(另见PEP8)你应该使用isinstance
而不是比较类型:
if isinstance(dict_foo[field], dict)
然而,这也会返回True
if dict_foo[field]
是一个子类dict
。如果你不想这样,你也可以使用is
代替==
。这会稍微快一些(并且可能不易察觉)。
如果您还想允许任意类似字典的对象,您可以更进一步并测试它是否是collections.abc.MutableMapping
。那将是True
for dict
and dict
子类以及显式实现该接口而无需子类化的所有可变映射dict
, 例如UserDict
:
>>> from collections import MutableMapping
>>> # from UserDict import UserDict # Python 2.x
>>> from collections import UserDict # Python 3.x - 3.6
>>> # from collections.abc import MutableMapping # Python 3.7+
>>> isinstance(UserDict(), MutableMapping)
True
>>> isinstance(UserDict(), dict)
False
就地修改并返回值
通常,函数要么就地修改数据结构or返回一个新的(修改后的)数据结构。仅举几个例子:list.append
, dict.clear
, dict.update
全部就地修改数据结构并且return None
。这使得跟踪函数的作用变得更加容易。然而,这并不是一个硬性规则,并且该规则总是存在有效的例外情况。然而我个人认为这样的函数不需要是一个例外,我会简单地删除return dict_del
line 并让它隐式返回None
,但是YMMV。
从字典中删除键
您复制了字典以避免在迭代期间删除键值对时出现问题。但是,正如另一个答案已经提到的,您可以迭代应删除的键并尝试删除它们:
for key in keys_to_remove:
try:
del dict[key]
except KeyError:
pass
这还有一个额外的优点,那就是你不需要嵌套两个循环(其中could会更慢,特别是当需要删除的键的数量很长时)。
如果你不喜欢空虚except
您还可以使用以下子句:contextlib.suppress(需要 Python 3.4+):
from contextlib import suppress
for key in keys_to_remove:
with suppress(KeyError):
del dict[key]
变量名称
我会重命名一些变量,因为它们不具描述性,甚至具有误导性:
delete_keys_from_dict
也许应该提到 subdict 处理,也许delete_keys_from_dict_recursive
.
dict_del
听起来像是被删除的字典。我倾向于更喜欢这样的名字dictionary
or dct
因为函数名称已经描述了对字典所做的操作。
lst_keys
,那里也一样。我可能会用keys
那里。如果你想更具体一些,比如keys_sequence
会更有意义,因为它接受任何sequence
(你只需要能够迭代它多次),而不仅仅是列表。
dict_foo
, 就是不行...
field
也不太合适,这是一个key.
把它们放在一起:
正如我之前所说,我个人会就地修改字典not再次归还字典。因此,我提出了两种解决方案,一种是就地修改它但不返回任何内容,另一种是创建一个删除键的新字典。
就地修改的版本(非常像 Ned Batchelders 的解决方案):
from collections import MutableMapping
from contextlib import suppress
def delete_keys_from_dict(dictionary, keys):
for key in keys:
with suppress(KeyError):
del dictionary[key]
for value in dictionary.values():
if isinstance(value, MutableMapping):
delete_keys_from_dict(value, keys)
返回一个新对象的解决方案:
from collections import MutableMapping
def delete_keys_from_dict(dictionary, keys):
keys_set = set(keys) # Just an optimization for the "if key in keys" lookup.
modified_dict = {}
for key, value in dictionary.items():
if key not in keys_set:
if isinstance(value, MutableMapping):
modified_dict[key] = delete_keys_from_dict(value, keys_set)
else:
modified_dict[key] = value # or copy.deepcopy(value) if a copy is desired for non-dicts.
return modified_dict
然而,它只制作字典的副本,其他值不会作为副本返回,您可以轻松地将它们包装在copy.deepcopy(我在代码的适当位置添加了注释)如果您愿意的话。