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.Mapping
对 collections
的作用?
似乎行 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 值,有 keys
、values
和 items
方法等)。这种类似于 dict
的对象可能会继承自 dict
,但它们不需要。
collections.abc
中的抽象类型是使用the top level abc
module实现的。 dict
被 register
编辑为 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']
>>>
现在您不需要知道正在使用的实际实现,只需知道它具有您想要的行为
我 运行 的代码是:
>>> from collections import abc
>>> mydict = {'test_key': 'test_value'}
>>> isinstance(mydict, abc.Mapping)
True
我了解 isinstance
的作用,但我不确定 abc.Mapping
对 collections
的作用?
似乎行 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 值,有 keys
、values
和 items
方法等)。这种类似于 dict
的对象可能会继承自 dict
,但它们不需要。
collections.abc
中的抽象类型是使用the top level abc
module实现的。 dict
被 register
编辑为 MutableMapping
(它是 Mapping
的子 class),因此 isinstance
检查将接受字典作为Mapping
即使 Mapping
不是 dict
.
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']
>>>
现在您不需要知道正在使用的实际实现,只需知道它具有您想要的行为