首先,我认为您的代码正在运行,而不是不优雅。没有直接的理由不使用您提供的代码。
但有几件事可能会更好:
比较类型
您的代码包含以下行:
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 的情况下显式实现该接口的可变映射,这将是True,例如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
就地修改并返回值
通常,函数要么就地修改数据结构或返回一个新的(修改后的)数据结构。举几个例子:list.append、dict.clear、dict.update都在原地修改数据结构和return None。这使得更容易跟踪函数的作用。但是,这不是一个硬性规则,并且该规则始终存在有效的例外情况。但是我个人认为这样的函数不需要是异常,我会简单地删除return dict_del 行并让它隐式返回None,但YMMV。
从字典中删除键
您复制了字典以避免在迭代期间删除键值对时出现问题。但是,正如另一个答案已经提到的,您可以遍历应该删除的键并尝试删除它们:
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 可能应该提到 subdict-handling,可能是 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) # 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 中(我在代码的适当位置添加了注释)。