“使用isinstance测试是否满足抽象基类的接口要求,往往比检查一个函数的参数是不是具体的dict类型要好,因为除了dict之外还有其他映射类型可用”,这段话出自《流畅的Python》第二版上册第3.4节“映射类型的标准API”中的“提示”。
这段话的意思是,使用 isinstance 来测试对象是否符合某个抽象基类(ABC)的接口要求,比直接检查对象是否是某个具体类型(例如 dict)更为灵活和通用。
让我们逐步分析这段话的含义:
一. isinstance 和抽象基类接口要求
抽象基类(ABC)是Python中用于定义接口的工具,它允许我们指定一个类必须实现的某些方法(抽象方法)。当使用 isinstance 来检查一个对象时,它不仅会检查对象是否是某个具体类的实例,还会检查它是否实现了该类所定义的接口(即继承关系)。
例如,假设你有一个抽象基类 Mapping(它可能是 collections.abc.Mapping)定义了字典的接口方法,如 getitem, iter, 和 len,你可以通过 isinstance 来检查一个对象是否是符合 Mapping 接口的实现。这样,即使这个对象不是具体的 dict 类型,只要它实现了这些方法,它就可以被认为是一个“字典类型”,也能通过 isinstance 检查。
from collections.abc import Mapping
#### 自定义一个类,模拟字典行为
class MyMapping(Mapping):
def __getitem__(self, key):
return "some value"
def __iter__(self):
return iter(["key1", "key2"])
def __len__(self):
return 2
obj = MyMapping()
print(isinstance(obj, Mapping)) # True
二. 直接检查 dict 类型的局限性
如果你仅仅检查一个对象是否是具体的 dict 类型(即 isinstance(obj, dict)),你只会识别出标准的字典对象,而无法识别其他也实现了字典行为的对象。例如,如果你定义了一个自定义类,它实现了字典接口的所有方法(比如 getitem, iter, 和 len),但是它不是标准的 dict 类型,那么通过 isinstance(obj, dict) 就无法识别它。
这就是为什么直接检查一个函数的参数是不是具体的 dict 类型可能不够灵活。因为 除了标准的 dict 类型,还有其他可以作为“映射类型”的对象,例如自定义的类,或是来自第三方库的类,它们实现了字典的接口,但不是 dict 类型。使用抽象基类(如 Mapping)可以帮助你更广泛地匹配符合接口要求的对象,而不仅仅是 dict。
三. 其他映射类型的可用性
dict 是一个典型的映射类型,但在Python中,映射类型不仅仅限于 dict。实际上,Python的标准库提供了多个实现了类似字典行为的类型,例如:
collections.defaultdict: 这是一个特殊的字典,它允许你为不存在的键设置默认值。
collections.OrderedDict: 这是一个有序字典,它保留插入顺序。
自定义的类:你可以实现一个自定义类,按照映射类型的接口来设计,比如支持通过键访问值。
通过 Mapping 这样的抽象基类,你不仅能匹配 dict 类型,还能匹配所有符合映射接口的对象,而不需要关心它们的具体类型。
四. 总结
这段话的核心意思是,通过抽象基类(例如 Mapping)和 isinstance 来测试对象是否实现了某个接口,比直接检查对象是否是某个具体类型(如 dict)更具灵活性。因为实现了特定接口的对象不仅限于某个具体类型,使用抽象基类可以让你更普遍地检查对象的接口,而不局限于某种实现类型。
例如,代码中的自定义类 MyMapping,虽然它不是 dict 类型,但它实现了字典的行为,使用 Mapping 抽象基类就能让你正确识别它是一个符合字典接口的对象。
基础扩展:
Mapping 是 dict 的父类。Mapping 是一个抽象基类,定义了字典类型应具备的一些核心接口(如 getitem、iter 和 len),而 dict 是 Mapping 的一个具体实现。所以,dict 继承自 Mapping,并且满足 Mapping 的接口要求。
994

被折叠的 条评论
为什么被折叠?



