在Python中如何检查变量是否是字典?
这是一个很好的问题,但不幸的是,被点赞最多的答案引出了一个糟糕的推荐,type(obj) is dict。
(注意,你也不应该使用dict作为变量名——它是内置对象的名称。)
如果您编写的代码将被其他人导入和使用,不要假定他们将直接使用内置的dict——这种假设会使您的代码更加不灵活,在这种情况下,会创建容易隐藏的错误,而不会使程序出错。
为了将来用户的正确性、可维护性和灵活性,我强烈建议,当代码中有更灵活、更习惯的表达式时,不要使用更不灵活、更不习惯的表达式。
Is是对对象同一性的测试。它不支持继承,不支持任何抽象,也不支持接口。
因此,我将提供几个选项。
支持继承:
这是我提出的第一个建议,因为它允许用户从collections模块中提供自己的dict子类,或者OrderedDict、defaultdict或Counter:
如果isinstance(any_object, dict):
但还有更灵活的选择。
支持抽象:
from collections.abc import Mapping
if isinstance(any_object, Mapping):
这允许代码的用户使用他们自己的抽象映射的自定义实现,它还包括dict的任何子类,并且仍然获得正确的行为。
使用界面
你经常听到面向对象的建议,“编程到接口”。
这种策略利用了Python的多态性或duck-typing。
因此,只需尝试访问接口,捕获特定的预期错误(如果没有.items,则捕获AttributeError,如果项目不可调用,则捕获TypeError),并进行合理的回退-现在任何实现该接口的类都会给你它的项目(注意.iteritems()在Python 3中消失了):
try:
items = any_object.items()
except (AttributeError, TypeError):
non_items_behavior(any_object)
else: # no exception raised
for item in items: ...
也许您会认为使用这样的duck-typing会产生太多的误报,这可能是真的,这取决于代码的目标。
结论
不要使用is检查标准控制流的类型。使用isinstance,考虑像Mapping或MutableMapping这样的抽象,并考虑完全避免类型检查,直接使用接口。