首页 > 其他 > 详细

剖析isinstance的实现机制

时间:2019-10-24 14:17:55      阅读:107      评论:0      收藏:0      [点我收藏+]

python的自省机制也是其一大彪悍的特性,对于任何一个对象,我们都可以准确的获取其类型。

print(type(123))
print(type(""))
print(type(str))
print(type(map))
"""
<class 'int'>
<class 'str'>
<class 'type'>
<class 'type'>
"""

但是这种获取方式有一个缺陷,比如说:

class A:
    pass


class B(A):
    pass


b = B()
print(type(b))  # <class '__main__.B'>

这里B继承自A,但是b是由B这个类实例化出来的,因此如果type(b)的话,打印的就是B这个类。但是我要怎么判断b和A之间的关系呢?

class A:
    pass


class B(A):
    pass


b = B()
print(isinstance(b, A))  # True

显然可以使用isinstance,如果A是B的父类,那么b不仅是B的实例对象,同时也是A的实例对象。但是这里问题就来了,这个isinstance的检测机制是什么?我们可以再来看一个例子。

from collections.abc import Iterable

s = ""
l = []
d = {}

print(isinstance(s, Iterable))
print(isinstance(l, Iterable))
print(isinstance(d, Iterable))
"""
True
True
True
"""

我们发现字符串对象、列表对象、字典对象都继承自Iterable,因为它们都是可迭代的的。因此这个isinstance比type的范围要更广泛一些,type得到的就是具体实例化该对象类,而isinstance则貌似是要求满足某种特定的要件就可以。我们来看一下源码。

class Iterable(metaclass=ABCMeta):

    __slots__ = ()

    @abstractmethod
    def __iter__(self):
        while False:
            yield None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Iterable:
            return _check_methods(C, "__iter__")
        return NotImplemented

class Sized(metaclass=ABCMeta):

    __slots__ = ()

    @abstractmethod
    def __len__(self):
        return 0

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Sized:
            return _check_methods(C, "__len__")
        return NotImplemented
    
    
class Container(metaclass=ABCMeta):

    __slots__ = ()

    @abstractmethod
    def __contains__(self, x):
        return False

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Container:
            return _check_methods(C, "__contains__")
        return NotImplemented

我们注意到这些都是一个抽象基类,里面定义了一个__subclasshook__方法,其实关键就在这里。

from abc import ABCMeta


class A(metaclass=ABCMeta):

    @classmethod
    def __subclasshook__(cls, C):
        # 当我们使用isinstance(obj, A)的时候
        # 那么实例化obj所对应类,就会作为参数传递给C
        # 我们可以自定义,比如这里
        # 如果C有fuck这个属性,那么就认为obj也是A的实例
        return hasattr(C, "fuck")


class S:

    def fuck(self):
        pass


s = S()
print(isinstance(s, A))  # True
# 我们注意到S这个类没有继承任何东西,但是它确是A的实例
# 因为我们自己实现了抽象基类

# 不仅如此,此时的S这个类还是A的子类
print(issubclass(S, A))  # True

以上です,希望各位能明白isinstance的机制。

技术分享图片

剖析isinstance的实现机制

原文:https://www.cnblogs.com/traditional/p/11731676.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!