首先,我认为你的代码运行良好且不失优雅。没有直接的理由不使用你提供的代码。
然而,以下几点可以改进:
比较类型
你的代码包含以下行:
if type(dict_foo[field]) == dict:
这可以被明显地改进。通常情况下(请参见 PEP8),您应该使用 isinstance
而不是比较类型:
if isinstance(dict_foo[field], dict)
如果dict_foo[field]
是dict
的子类,==
运算符也会返回True
。如果不想这样做,您可以改用is
运算符。这将稍微快一点(可能不太明显)。
如果您还想允许任意的类dict对象,您可以进一步测试它是否是collections.abc.MutableMapping
的实例。这将对于dict
和dict
的子类以及所有显式实现了该接口而没有继承dict
的可变映射(例如UserDict
)都返回True
:
>>> from collections import MutableMapping
>>>
>>> from collections import UserDict
>>>
>>> isinstance(UserDict(), MutableMapping)
True
>>> isinstance(UserDict(), dict)
False
原地修改和返回值
通常函数要么在原地修改数据结构,要么返回新的(经过修改的)数据结构。举几个例子: list.append
,dict.clear
,dict.update
都会原地修改数据结构并返回None
。这使得更容易跟踪函数的行为。但这不是一个硬性规则,总有例外情况。然而个人认为像这样的函数不需要成为这个例外, 我会简单地移除return dict_del
行,并让它隐式地返回None
,但您的情况可能不同。
从字典中删除键
您复制了字典以避免迭代期间删除键值对时出现问题。然而,正如其他答案已经提到的,您可以直接迭代应该被删除的键并尝试删除它们:
for key in keys_to_remove:
try:
del dict[key]
except KeyError:
pass
这样做的额外优点是您不需要嵌套两个循环(可能会更慢,特别是当需要删除的键的数量非常多时)。
如果您不喜欢空的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
应该可能提到子字典处理,可以改成 delete_keys_from_dict_recursive
。
dict_del
听起来像是一个删除的字典。我倾向于使用类似 dictionary
或 dct
这样的名称,因为函数名称已经描述了对字典所做的操作。
lst_keys
,同样如此,我可能只会使用 keys
。如果你想要更加具体的话,例如 keys_sequence
会更有意义,因为它接受任何 sequence
(您只需要能够多次迭代它),而不仅仅是列表。
dict_foo
简直不行...
field
也不太合适,它是一个键。
综合考虑:
正如我之前所说,我个人会就地修改字典,而不是返回字典。因此,我提供了两种解决方案,一种是就地修改它而不返回任何内容,另一种则是创建一个新的字典并删除其中的键。
就地修改的版本(非常类似于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)
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
return modified_dict
然而它只复制字典,其他值不会作为副本返回,如果你希望这些值也被复制,你可以很容易地在这些值上使用copy.deepcopy
进行深拷贝(我已在代码的适当位置放置了注释)。
isinstance(spam,collections.MutableMapping)
来使其更具多态性。 - Katriel