如何检查变量是不是是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 子类,或者集合模块中的 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
之类的抽象,并考虑完全避免类型检查,直接使用接口。
【讨论】:
对选择的书面说明,以及何时/为什么选择它们。 我认为下结论“不要使用是检查标准控制流的类型”太快了。我们需要逐案评估基础知识。在某些情况下,更希望有一个严格的检查控制,您希望确保它是 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中的字典?的主要内容,如果未能解决你的问题,请参考以下文章