如何检查变量是否是Python中的字典?


214

您如何检查变量是否是python中的字典?

例如,我希望它遍历字典中的值,直到找到字典为止。然后,遍历找到的内容:

dict = {'abc': 'abc', 'def': {'ghi': 'ghi', 'jkl': 'jkl'}}
for k, v in dict.iteritems():
    if ###check if v is a dictionary:
        for k, v in v.iteritems():
            print(k, ' ', v)
    else:
        print(k, ' ', v)

也是stackoverflow.com/questions/378927/…(被标记为上述副本的副本)。
NPE


40
不,这不是同一个问题。该问题的答案以及此处列出的其他问题的答案都包含基本上相同的信息。但是“如何检查变量是否为python中的字典”的答案是“使用type()或isinstance()”,这将导致一个新问题,即type()和isinstance()有什么区别? 。但是提出第一个问题的人可能无法知道,直到第一个问题得到回答。嗯,不同的问题,在您在网站上寻找问题时很重要。

13
我同意@mbakeranalecta的意思,我是来这里寻找问题的答案的:“如何检查变量是否是Python中的字典?” 而且我从没想过要对“ python中的isinstance()和type()之间的差异”做出回答。
lodebari

5
要检查变量是否特别是字典,您可能应该使用isinstance(v, collections.abc.Mapping)。换句话说,这与“ isinstance()和type()之间的差异”不完全相同。
乔什·凯利

Answers:


279

您可以使用if type(ele) is dict或使用isinstance(ele, dict)将子类化后将起作用的方法dict

d = {'abc':'abc','def':{'ghi':'ghi','jkl':'jkl'}}
for ele in d.values():
    if isinstance(ele,dict):
       for k, v in ele.items():
           print(k,' ',v)

70
我否决了这个答案,因为对一般问题的正确答案是:isinstance(ele, collections.Mapping)。它的工作原理为dict()collections.OrderedDict()collections.UserDict()。问题中的示例足以使帕德里亚克的答案起作用,但对于一般情况而言还不够好。
亚历山大·里佐夫

3
我不赞成这个答案,因为如果您要调用ele.items()为什么要检查类型?EAFP /鸭打字在这里工作,只是包装for k,v in ele.items()try...except (AttributeError, TypeError)。如果引发异常,您会知道ele没有items
哪个

@Padraic Cunningham您的假设边缘情况将要求您的“ 100%不是字典”自定义类1.具有items()方法2.恰好产生一个可迭代对象,并且3.该可迭代对象的每个元素都可以表示为2 -元组。至此,您的自定义对象已经实现了dict的一半。对于列出的代码,我们只关心嵌套元素的条件扩展,而您的自定义对象已经实现了。(您批评@Alexander Ryzhov的评论过于笼统,但现在提出了笼统的说法,有点讽刺意味)
cowbert

1
@PadraicCunningham我宁愿不教那些不太熟悉Python反模式的人。Python中很少有需要显式类型检查的用例-多数源自继承不良的实现(例如“神对象”,重写标准库/语言构造等)。最初的问题本身就是XY问题。为什么OP需要检查类型?因为根据他们的代码,他们真正想要做的是检查其集合中的项目是否表现得像一个集合(items()产生嵌套可迭代的实现)。
cowbert

4
@AlexanderRyzhov为什么不发布该方法作为答案?顺便说一句,正如Josh Kelley 在上面的建议中所评论的那样collections.abc.Mapping,请注意它们是相同的,但collections.abc在Python 3.3之前不可用。collections.Mapping别名在Python 3.6中仍然可用,但没有记录,因此可能应该首选collections.abc.Maping
Yushin Washio

4

您如何检查变量是否是Python中的字典?

这是一个很好的问题,但不幸的是,最受支持的答案导致推荐不力type(obj) is dict

(请注意,您也不应将其dict用作变量名-这是内置对象的名称。)

如果您正在编写将要由其他人导入和使用的代码,请不要假定他们将直接使用内置的dict-假定这种假定会使您的代码更加不灵活,在这种情况下,请创建容易隐藏的错误,这些错误不会使程序出错。

我强烈建议,出于将来用户的正确性,可维护性和灵活性的目的,当存在更灵活,惯用的表达式时,请不要在代码中使用较不灵活,唯一的表达式。

is是对对象身份的测试。它不支持继承,不支持任何抽象,并且不支持接口。

因此,我将提供几种选择。

支持继承:

这是第一个建议,我会做,因为它允许用户提供自己的字典的子类,或者OrderedDictdefaultdict或者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,并考虑直接使用接口完全避免类型检查。


3

OP没有排除起始变量,因此为了完整起见,这里是如何处理处理可能包含条目作为字典的假定字典的一般情况。

还遵循上述注释中纯Python(3.8)建议的测试字典的方法

from collections.abc import Mapping

dict = {'abc': 'abc', 'def': {'ghi': 'ghi', 'jkl': 'jkl'}}

def parse_dict(in_dict): 
    if isinstance(in_dict, Mapping):
        for k, v in in_dict.items():
            if isinstance(v, Mapping):
                for k, v in v.items():
                    print(k, v)
            else:
                print(k, v)

parse_dict(dict)

dict.iteritems()在Python 3中不存在,应dict.items()改为使用。
Arkelis

@Arkelis Oops,刚刚复制/粘贴了该部分,感谢您指出它-现在已更正。
CodeMantle
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.