isinstance with a dictionary and abc.Mapping from collections 做什么?

What does isinstance with a dictionary and abc.Mapping from collections doing?

我 运行 的代码是:

>>> from collections import abc
>>> mydict = {'test_key': 'test_value'}
>>> isinstance(mydict, abc.Mapping)
True

我了解 isinstance 的作用,但我不确定 abc.Mappingcollections 的作用?

似乎行 isinstance(mydict, abc.Mapping) 被用来检查 mydict 是一个字典?

这样做岂不是更简单 isinstance(mydict, dict)?

我进行了一些搜索并在此线程中找到了相关评论:What is the best (idiomatic) way to check the type of a Python variable?,但我仍然无法弄清楚为什么在这里使用 abc.Mapping 比仅使用 dict 更可取.

collections.abc.Mapping是首选,因为它为这种类型的容器定义了抽象api,因为dict只是这样一个实现容器。有点过于简单化,但这是关键 - dict 不是 interface/abstract/api/...

不是 dict 实例的对象示例是 MultiDict,广泛用于网络框架(例如 aiohttp)。

collections.abc模块提供了几个抽象基classes,可用于一般描述Python中的各种数据结构。在您的示例中,您测试对象是否是 Mapping 抽象 class 的实例,这对于许多 class 是 "work like a dictionary" 的实例(例如,它们有一个 __getitem__ 方法采用可散列键和 return 值,有 keysvaluesitems 方法等)。这种类似于 dict 的对象可能会继承自 dict,但它们不需要。

collections.abc中的抽象类型是使用the top level abc module实现的。 dictregister 编辑为 MutableMapping(它是 Mapping 的子 class),因此 isinstance 检查将接受字典作为Mapping 即使 Mapping 不是 dict.

的实际基础 class

collections.abc 为容器

提供一系列抽象基础类

This module provides abstract base classes that can be used to test whether a class provides a particular interface; for example, whether it is hashable or whether it is a mapping.

它们允许您检查某个对象是否具有与您正在检查的 ABC 类似的行为,而无需关心实际实现。

例如,假设你有一个函数 F 根据参数的类型做一些事情,你可以直接检查它是否是 list 或 tuple 或 dict 等的实例,然后做你的工作,但是限制你只能使用那些,如果你然后制作你自己的 class 具有类似行为的列表,在某些情况下你关心并想与 F 一起使用它,你会发现它不行不通,那么你必须修改 F 以接受你的 class,但如果你改为检查 ABC,则不需要这样的修改

现在是一个有效的例子:假设你想要一个函数来给出列表中偶数位置的所有元素,那么你可以这样做

def even_pos(data):
    if isinstance(data,list):
        return [data[i] for i in range(0,len(data),2)]
    else:
        raise ValueError("only a list")

并用作

>>> test = list(range(20))
>>> even_pos(test)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>

没问题,但后来你意识到元组与列表在 this 函数中的作用相同,你也可以将检查添加到函数中,一切都很好,但后来你的朋友告诉你他想使用您的功能,但他使用的是 collections.deque 然后您的另一个朋友告诉...看到这里的模式了吗?我提到的所有对象(列表、元组、双端队列)都有相同的东西,并且可以通过该示例函数以相同的方式使用,并且所有这些行为都在 ABC 中压缩,所以 isinstance(data,(list,tuple,collections.deque,...) 你只需要 isinstance(data,abc.Sequence) 函数看起来像

from collections import abc
def even_pos(data):
    if isinstance(data,abc.Sequence):
        return [data[i] for i in range(0,len(data),2)]
    else:
        raise ValueError("only a Sequence")

>>> even_pos( list(range(10)) )
[0, 2, 4, 6, 8]
>>> even_pos( tuple(range(10)) )
[0, 2, 4, 6, 8]
>>> even_pos( range(10) )  # in python 3 range don't return a list, but a range object
[0, 2, 4, 6, 8]
>>> even_pos( "asdfghjh" )
['a', 'd', 'g', 'j']
>>> 

现在您不需要知道正在使用的实际实现,只需知道它具有您想要的行为