the1fire

基于Django的个人博客系统

抽象基类以及isinstance和type的区别

分类:Python   作者:edward   创建时间:2019年5月8日 15:41   pv:116   uv:116

抽象基类

我们在某些情况下需要判断某个对象的类型 我们去判断某种类的类型的时候,如果没有抽象基类的话,我们就必须去写hasattr这种方法,但实际上使用isinstance(Python内置函数,判断类型)是更好的。

class Company(object):
    def __init__(self, employee_list):
        self.employee = employee_list

    def __len__(self):
        return len(self.employee)


com = Company(['mark1', 'mark2'])
print(hasattr(com, '__len__'))  # True
print(len(com))

# 使用场景
from collections.abc import Sized  #

#  我们在某些情况下需要判断某个对象的类型
print(isinstance(com, Sized))  # True  是根据com有没有__len__判断出来的。
# 说白了还是利用了鸭子类型,鸭子类型才是Python语言的根本

我们需要强制某个子类必须实现某些方法 比如实现一个web框架,集成cache(redis,mysql,cache),我们需要设计一个抽象基类,指定子类必须实现某些方法。

import abc


class CacheBase(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def get(self, key, value):
        pass

    @abc.abstractmethod
    def set(self, key, value):
        pass


class RedisCache(CacheBase):
    def get(self, key, value):
        pass

    def set(self, key, value):
        pass


# 初始化的时候就会检查有没有实现get和set方法,没有实现的话就会报错
redis_cache = RedisCache()

抽象基类给我们带来的最大的两个好处:

  1. 调用isinstance()。
  2. 用来做接口的强制规定。

最后,不推荐使用抽象基类。 即使在Python中,它也不是用来继承的,而是用来让我们理解Python里面的继承关系以及这些接口的定义

尽量使用鸭子类型,如果实在要使用这些接口,推荐用Mixin, 用多继承的方法去实现它。 因为抽象基类很容易设计过度,反而不容易去理解。

在Python中已经实现了一些通用的抽象基类,全都放在collections.abc中。

isinstance和type的区别

我们应该尽量用isinstance()来判断类型。type()会有误差。请见下面代码:

class A:
    pass


class B(A):
    pass


b = B() 

# 可以把类B理解为模板对象,因为它在全局中只有一个

print(type(b) is B)  # True  # 应该使用is而不是==。因为is是判断id(内存地址)是否相等,而==判断的是值是否相等。
print(type(b) is A)  # False # B和A是两个不同的对象,它们两个的id不相等。

print(isinstance(b, B))  # True
# isinstance这个函数在内部会去检查继承链
print(isinstance(b, A))  # True