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

Ril*_*ley 156 python dictionary

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

例如id喜欢它循环遍历字典中的值,直到它找到一个字典,然后遍历它找到的那个:

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)
Run Code Online (Sandbox Code Playgroud)

Pad*_*ham 198

您可以使用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)
Run Code Online (Sandbox Code Playgroud)

  • 我对这个答案进行了投票,因为对一般问题的正确答案是:`isinstance(ele,collections.Mapping)`.它适用于`dict()`,`collections.OrderedDict()`和`collections.UserDict()`.问题中的例子对于Padriac的工作答案来说足够具体,但对于一般情况来说这还不够好. (55认同)
  • @cowbert,欢迎您提出意见,但这实际上是Padraic回答了这个问题 (8认同)
  • @AlexanderRyzhov为什么不发布该方法作为答案?顺便提一下,乔什·凯利(Josh Kelley)[上面已经评论过](/sf/ask/1766239261/#comment74495204_25231989)暗示了“收藏”。 abc.Mapping`,可能需要注意它们是相同的,但是在Python 3.3之前不支持`collections.abc`。“ collections.Mapping”别名在Python 3.6中仍然可用,但没有记录,因此可能应该更喜欢“ collections.abc.Maping”。 (4认同)
  • 我不赞成这个答案,因为如果您要调用`ele.items()`,为什么要检查类型?EAFP / duck-typing在这里起作用,只需将try,ele.items()中的k,v换成try ...,除了(AttributeError,TypeError)。如果引发异常,则您知道`ele`没有`items`会产生可迭代的... (3认同)

Aar*_*all 54

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

这是一个很好的问题,但不幸的是,最受好评的答案导致了一个糟糕的推荐,type(obj) is dict

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

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

我强烈建议,为了未来用户的正确性、可维护性和灵活性,当有更灵活的惯用表达式时,永远不要在代码中使用不那么灵活的单惯表达式。

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

所以我将提供几个可以做到的选项。

支持继承:

这是我要提出的第一个建议,因为它允许用户提供他们自己的 dict 子类,或者 a OrderedDict, defaultdict,或者Counter来自 collections 模块:

if isinstance(any_object, dict):

但还有更灵活的选择。

支持抽象:

from collections.abc import Mapping

if isinstance(any_object, Mapping):
Run Code Online (Sandbox Code Playgroud)

这允许您的代码用户使用他们自己的抽象 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: ...
Run Code Online (Sandbox Code Playgroud)

也许您可能认为使用像这样的鸭子类型在允许太多误报方面做得太过分了,而且可能是这样,这取决于您对此代码的目标。

结论

不要is用于检查标准控制流的类型。使用isinstance,考虑像Mappingor 的抽象MutableMapping,并考虑完全避免类型检查,直接使用接口。


小智 7

在Python 3.6中

    typeVariable = type(variable)
    
    print('comparison',typeVariable == dict)

    if typeVariable == dict:
        #'true'
    else:
        #'false'
Run Code Online (Sandbox Code Playgroud)


Cod*_*tle 6

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

还遵循上述评论中的纯 Python(3.8)推荐方法来测试字典。

from collections.abc import Mapping

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

def parse_dict(in_dict): 
    if isinstance(in_dict, Mapping):
        for k_outer, v_outer in in_dict.items():
            if isinstance(v_outer, Mapping):
                for k_inner, v_inner in v_outer.items():
                    print(k_inner, v_inner)
            else:
                print(k_outer, v_outer)

parse_dict(my_dict)
Run Code Online (Sandbox Code Playgroud)