我们的gzh是向阳三只大明白,满满满是干货,分享近期的学习常识以及个人总结(包括读研和IT),期望我们一同努力,一同加油!求关注!!

type

type办法有两种重载方式:

  1. type(o: object)
  2. type(name: str, bases:Tuple[type, ...], dict:Mapping[str: Any], **kwds)

运用第一种重载方式的时分,传入一个【object】类型,回来一个【type】目标,一般与object.__class__办法的回来值相同。

运用第二种重载方式的时分,也会得到一个【type】目标,本质上来说这是一种动态类,参数意义如下:

  • name:字符型,指定动态类的类名,也是该动态类的__name__特点;
  • bases:type类型元祖,指定动态类承继的父类,也是该动态类的__bases__特点;
  • dict:字典类型,指定动态类的特点和办法界说,经过必定的包装后成为动态类的__dict__特点;

示例

重载方式1

class A(object):
  pass
​
a = A()
print(type(a), a.__class__, type(A))
-----------------------------
<class '__main__.A'> <class '__main__.A'> <class 'type'>

重载方式2

class OldClass(object):
  a = 1def __init__(self) -> None:
    self.name = "OldClass"def get_name(self):
    return self.name
​
​
my_dynamic_cls = type('DynamicClass', (OldClass,),
           dict(name='dynamic', a=2, b=3, c=4))
​
new_obj = my_dynamic_cls()
print(my_dynamic_cls.__dict__)
print(new_obj.__dict__, type(new_obj))
-----------------------------
{'name': 'dynamic', 'a': 2, 'b': 3, 'c': 4, '__module__': '__main__', '__doc__': None}
{'name': 'OldClass'} <class '__main__.DynamicClass'>

在上面的示例中我们运用type成功发明了一个动态类并添加了几个类特点,因为指定了【OldClass】作为父类,所以动态生成的类也具有【OldClass】的全部特性。

动态生成一个类的时分不但能够指定类特点,还能够绑定类办法,示例如下:

class OldClass(object):
  a = 1def __init__(self) -> None:
    self.name = "OldClass"def get_name(self):
    return self.name
​
def print_msg(msg: str) -> None:
  print(msg)
​
my_dynamic_cls = type('DynamicClass ', (OldClass,),
           dict(name='dynamic', a=2, b=3, c=4, method=print_msg))
​
new_obj = my_dynamic_cls()
my_dynamic_cls.method("运用动态绑定的办法!!")
print(my_dynamic_cls.__dict__)
-----------------------------
运用动态绑定的办法!!
{'name': 'dynamic', 'a': 2, 'b': 3, 'c': 4, 'method': <function print_msg at 0x00000188189F73A0>, '__module__': '__main__', '__doc__': None}

isinstance

Return True if the object argument is an instance of the classinfo argument, or of a (direct, indirect, or virtual) subclass thereof. If object is not an object of the given type, the function always returns False. If classinfo is a tuple of type objects (or recursively, other such tuples) or a union of multiple types, return True if object is an instance of any of the types. If classinfo is not a type or tuple of types and such tuples, a TypeError exception is raised. TypeError may not be raised for an invalid type if an earlier check succeeds.

——PythonDoc

isinstance办法用来查看给定的目标是否是给定类型的实例或许是给定类型的恣意子类的实例,一般运用该办法进行目标类型校验。

示例

class AMetaClass(type):
​
  def __new__(cls, *args, **kwargs):
    return type.__new__(cls, *args, **kwargs)
​
​
class BMetaClass(AMetaClass):
  pass
​
​
class AClass(object, metaclass=BMetaClass):
​
  def __init__(self, name: str) -> None:
    self.name = name
​
​
class BClass(AClass):
​
  def __init__(self, name: str) -> None:
    super().__init__(name)
    
obj_a = AClass('a')
obj_b = BClass('b')
-----------------------------
print(isinstance(obj_b, AClass)) -> True
print(isinstance(obj_b, BClass)) -> True
print(isinstance(obj_b, AMetaClass)) -> False
print(isinstance(obj_b, BMetaClass)) -> False
print(isinstance(obj_b, type)) -> False
print(isinstance(BClass, AMetaClass)) -> True
print(isinstance(BClass, BMetaClass)) -> True
print(isinstance(BClass, type)) -> True

总结一下,isinstance办法查看的规模便是参数的模板层按照承继联系进行检索。

issubclass

issubclass(class: type, classinfo: Union[type, ...])办法用来判断指定的两个类型之间的从属联系,如果【class】是【classinfo】的子类回来真(True),不然回来假(False)。

有几点注意事项这里说一下:

  1. issubclass(cls, cls)回来是真;
  2. 【classinfo】参数能够是一个type元祖,只要有一个条件为真,则表达式结果为真;
  3. 【class】和【classinfo】有必要是元类或许类,不能是一个目标,总结一下便是参数要么是【type】的子类要么是【type】的实例;

示例

class AMetaClass(type):
​
  def __new__(cls, *args, **kwargs):
    return type.__new__(cls, *args, **kwargs)
​
​
class BMetaClass(AMetaClass):
  pass
​
​
class AClass(object, metaclass=BMetaClass):
​
  def __init__(self, name: str) -> None:
    self.name = name
​
​
class BClass(AClass):
​
  def __init__(self, name: str) -> None:
    super().__init__(name)
    
obj_a = AClass('a')
obj_b = BClass('b')
-----------------------------
​
issubclass(AMetaClass, type) -> True
issubclass(BMetaClass, type) -> True
issubclass(BMetaClass, AMetaClass) -> True
issubclass(AClass, AMetaClass) -> False
issubclass(AClass, BMetaClass) -> False
issubclass(BClass, AClass) -> True
issubclass(AClass, obj_a) -> TypeError: arg 2 must be a class
issubclass(obj_a, AClass) -> TypeError: arg 1 must be a class

从程序结果能够看到传入元类和类回来永远是假,而且不能直接传入目标。

归纳示例

为了更好的让我们明白这三者之间的区别和联系,我画了一张图

【Python】type、isinstance、issubclass详解
这是初始状况,界说了三个目标,三个类和三个元类,它们之间的联系如上图所示;

class M1(type):
​
  def __new__(cls, *args, **kwargs):
    return type.__new__(cls, *args, **kwargs)
​
​
class M2(M1):
  pass
​
​
class M3(type):
​
  def __new__(cls, *args, **kwargs):
    return type.__new__(cls, *args, **kwargs)
​
​
class C1(metaclass=M3):
  pass
​
​
class C2(C1):
  pass
​
​
class C3(metaclass=M2):
  pass
​
​
o1 = C1()
o2 = C2()
o3 = C3()

isinstance

针对目标

以【O2】为例,它的检索规模如下图红线所示:

【Python】type、isinstance、issubclass详解

针对类

以【C3】为例,它的检索规模如下图红线所示:

【Python】type、isinstance、issubclass详解

issubclass

针对类

以【C2】为例,回来真值的规模如下:

【Python】type、isinstance、issubclass详解

针对元类

以【M2】为例,回来真值的规模如下:

【Python】type、isinstance、issubclass详解

总结

调用type办法

  1. 如果是目标,则会顺着实例化的逆方向寻觅,也便是找到创立它的类;
  2. 如果是类,则会顺着承继逆方向寻觅,直到找到它的元类。

调用isinstance办法

  1. 如果是目标,那么实例化它的类和该类的一切父类都回来真,也便是沿着承继途径上都是回来真,但 不能是元类;
  2. 如果是类,那么就找其元类的承继途径,途径上一切的元类都回来真。

调用issubclass办法

  1. 参数有必要是同一个类型,元类或许类;
  2. 按照承继途径进行判断。

文中难免会出现一些描述不当之处(尽管我已重复查看多次),欢迎在留言区纠正,相关的常识点也可进行分享。