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

Posted

技术标签:

【中文标题】如何检查变量是不是是Python中的字典?【英文标题】:How to check if a variable is a dictionary in Python?如何检查变量是否是Python中的字典? 【发布时间】:2014-10-03 14:45:52 【问题描述】:

如何检查一个变量是否是 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)

【问题讨论】:

还有***.com/questions/378927/…(标记为与上述重复)。 还有***.com/q/2225038/770830 不,这不是同一个问题。这个问题和这里列出的其他问题的答案都包含基本相同的信息。但是“如何检查变量是否是 python 中的字典”的答案是“使用 type() 或 isinstance()”,这会导致一个新问题,即 type() 和 isinstance() 之间的区别是什么.但是,在第一个问题得到回答之前,提出第一个问题的人不可能知道这一点。因此,不同的问题,当您在网站上寻找问题时,这很重要。 我同意@mbakeranalecta 我来这里是为了寻找“如何检查变量是否是 Python 中的字典?”问题的答案。而且我从来没有想过将我的答案看成“python 中 isinstance() 和 type() 之间的差异”。 为了检查一个变量是否特别是一个字典,你应该使用isinstance(v, collections.abc.Mapping)。换句话说,这不是“isinstance() 和 type() 之间的差异”的完全重复。 【参考方案1】:

您可以使用if type(ele) is dict 或使用isinstance(ele, dict),如果您将dict 子类化,这将起作用:

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

【讨论】:

我否决了这个答案,因为一般问题的正确答案是:isinstance(ele, collections.Mapping)。它适用于dict()collections.OrderedDict()collections.UserDict()。问题中的示例对于 Padriac 的回答来说足够具体,但对于一般情况来说还不够好。 我否决了这个答案,因为如果你要调用ele.items(),你为什么要检查类型? EAFP/duck-typing 在这里工作,只需将 for k,v in ele.items() 包裹在 try...except (AttributeError, TypeError) 中。如果引发异常,您知道 ele 没有产生可迭代的 items... @Padraic Cunningham 您假设的边缘情况将要求您的“100% 不是 dict”自定义类 1. 有一个 items() 方法 2. 恰好产生一个可迭代的和 3. 其中该可迭代对象的每个元素都可以表示为 2 元组。此时您的自定义对象已经实现了一半的字典。出于列出代码的目的,我们只关心嵌套元素的条件扩展,并且您的自定义对象已经实现了它。 (有点讽刺意味的是,您批评@Alexander Ryzhov 的评论过于笼统,但现在提出了一般情况) @PadraicCunningham 我宁愿不教那些不熟悉 Python 反模式的人。 Python 中很少有需要 显式类型检查的用例——大多数源于继承了一个糟糕的实现(“上帝对象”、覆盖标准库/语言结构等)。最初的问题是本身就是一个 XY 问题。为什么OP需要检查类型?因为根据他们的代码,他们真正想做的是检查他们的集合中的项目是否表现像一个集合(实现items(),产生一个嵌套的迭代)。 @AlexanderRyzhov 为什么不发布这种方法作为答案?顺便说一句,作为 Josh Kelley has commented above 建议 collections.abc.Mapping,请注意它们是相同的,但 collections.abc 在 Python 3.3 之前不可用。 collections.Mapping 别名在 Python 3.6 中仍然可用,但没有记录,所以可能有人应该更喜欢 collections.abc.Maping【参考方案2】:

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

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

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

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

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

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

所以我将提供几个选项。

支持继承:

这是我要提出的第一个建议,因为它允许用户提供自己的 dict 子类,或者集合模块中的 OrderedDictdefaultdictCounter

if isinstance(any_object, dict):

但还有更灵活的选择。

支持抽象:

from collections.abc import Mapping

if isinstance(any_object, Mapping):

这允许您的代码用户使用他们自己的抽象映射的自定义实现,其中还包括dict 的任何子类,并且仍然获得正确的行为。

使用界面

您通常会听到 OOP 建议,“编程到接口”。

此策略利用了 Python 的多态性或鸭子类型。

所以只需尝试访问接口,捕获特定的预期错误(AttributeError,以防没有.itemsTypeError,以防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,考虑MappingMutableMapping 之类的抽象,并考虑完全避免类型检查,直接使用接口。

【讨论】:

对选择的书面说明,以及何时/为什么选择它们。 我认为下结论“不要使用是检查标准控制流的类型”太快了。我们需要逐案评估基础知识。在某些情况下,更希望有一个严格的检查控制,您希望确保它是 1 并且只有 1 类型,但不包括其子项。 此时,随着 mypy 的静态类型检查和 match 出现支持继承的案例,这个答案需要稍微更新一下。【参考方案3】:

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

同样按照纯Python(3.8)recommended way来测试上述cmets中的字典。

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)

【讨论】:

dict.iteritems() 在 Python 3 中不存在,您应该改用 dict.items() @Arkelis 糟糕,刚刚复制/粘贴了该部分,感谢您指出 - 现在更正。 关于化妆品的评论——在我看来,k,v 在嵌套循环中的重复使用看起来很时髦。这也意味着在显示的列表中,内部print(k,v) 不代表外部k @JesseChisholm,完全正确,需要调整(完成)! typing.Mapping有什么区别?【参考方案4】:

在 python 3.6 中

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

    if typeVariable == dict:
        #'true'
    else:
        #'false'

【讨论】:

【参考方案5】:

我的测试发现这可以工作,现在我们有类型提示:

from typing import Dict

if isinstance(my_dict, Dict):
    # True
else:
    # False

附注一些关于打字的讨论。Dict here

【讨论】:

以上是关于如何检查变量是不是是Python中的字典?的主要内容,如果未能解决你的问题,请参考以下文章

检查一个键是不是存在并且它的值不是 Python 字典中的空字符串

如何检查字典python中是不是存在多个值

Python:将字典中的变量加载到命名空间中

检查列中的单词是不是与字典中的单词匹配

如何检查字典中的值是不是大于传递的值

如何检查 NSDictionary 中的值是不是存在于字典数组中