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