详解Python是如何实现issubclass的


Posted in Python onJuly 24, 2019

使用Python内置的issubclass方法很方便的检测一个类是否是另一个类的子类。

这个是issubclass的文档:

issubclass(class, classinfo)

Return true if class is a subclass (direct, indirect or virtual) of classinfo. A class is considered a subclass of itself. classinfo may be a tuple of class objects, in which case every entry in classinfo will be checked. In any other case, a TypeError exception is raised.

一个类的子类可以是直接的、间接的、或者是虚拟的。

issubclass的第二个参数classinfo可以是一个类对象或者包含类对象的tuple(只要其中一个检测成功即返回True)。

一些使用示例:

>>> class A(object):
...   pass
...
>>> class B(A):
...   pass
...
>>> class C(B, A):
...   pass
...
>>> class D(C):
...   pass
...
>>> issubclass(D, D), issubclass(D, C), issubclass(D, B), issubclass(D, A), issubclass(D, object)
(True, True, True, True, True)
>>> D.__bases__
(<class '__main__.C'>,)
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

D是D的子类,D定义时的基类是C,所以D是C的子类,而且D是B,A,object的间接子类。

__mro__是类属性, 在类定义完毕Python解析器便通过一种C3算法将所有的父类以method resolution order的顺序保存到一个元组里, 成为类的属性。

所以issubclass可以这样简单的实现:

def issubclass(cls, classinfo):
  if classinfo in cls.__mro__:
    return True
  return False

Python的issubclass是内置函数(一般是C实现),实际上要复杂很多,要检测参数类型,如第一个参数必须是type类型,第二个参数是type类型或者tuple类型。还要考虑该类是否是虚拟的子类,以及子类的子类。

例如:

>>> from collections import abc
>>> class E:
...   def __len__(self):
...     return 1
...
>>> issubclass(E, abc.Sized)
True
>>> E.__mro__
(<class '__main__.E'>, <class 'object'>)
>>> class F:
...   pass
...
>>> issubclass(F, abc.Sized)
False
>>> abc.Sized.register(F)
<class '__main__.F'>
>>> issubclass(F, abc.Sized)
True

Python是动态类型语言,长久以来使用Duck type(鸭子类型)形式编程,不管对象是什么类型,只要实现了所需要的方法。

现在有了ABCs, 可以用于判断某个类或者某个对象是不是ABCs的子类或者实例,但这个类并不需要显示的继承于ABCs, 因为python内置的ABCs有一种注册机制可将一个类注册为它的子类。如上例子的register方法。

还有一种机制是可以定制一个__subclasshook__方法,将某种类型的类认定为子类。

如abc.Sized的__subclasshook__是这样子的:

@classmethod
def __subclasshook__(cls, C):
  if cls is Sized:
    if any("__len__" in B.__dict__ for B in C.__mro__):
      return True
  return NotImplemented

所以有__len__方法的E类是abc.Sized的子类, 这个__subclasshook__方法是通过__subclasscheck__方法调用的,这个__subclasscheck__是每一个ABC类都有的方法,在ABCMeta类(其他ABC类都继承于它)实现。

现在的issubclass函数的实现,会先判断classinfo是否有__subclasscheck__方法,如果有此方法,则判断子类的逻辑由该方法返回,即覆盖issubclass的实现(CPython)。

__subclasscheck__会分几个步骤进行判断:

  1. 调用__subclasshook__方法,如果有方法定义
  2. 检查自己是否在待检测类的__mro__列表里
  3. 递归检查待检测类是否是在注册子类(内置_abc_registry列表属性)
  4. 递归检查待检测类是否是自己子类的子类

具体源码在: https://github.com/python/cpython/blob/3.6/Lib/abc.py#L194-L231

相关的CPython实现在: https://github.com/python/cpython/blob/0ccc0f6c7495be9043300e22d8f38e6d65e8884f/Objects/abstract.c#L2223

而基本上isinstance(object, classinfo)方法的实现只需要调用issubclass(type(object), classinfo)

参考:

29.7. abc — Abstract Base Classes : https://docs.python.org/3/library/abc.html
PEP 3119 ? Introducing Abstract Base Classes: https://www.python.org/dev/peps/pep-3119/

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python赋值语句后逗号的作用分析
Jun 08 Python
Python处理json字符串转化为字典的简单实现
Jul 07 Python
python获取多线程及子线程的返回值
Nov 15 Python
python链接oracle数据库以及数据库的增删改查实例
Jan 30 Python
python实现简单登陆流程的方法
Apr 22 Python
python点击鼠标获取坐标(Graphics)
Aug 10 Python
python3 map函数和filter函数详解
Aug 26 Python
Python类和实例的属性机制原理详解
Mar 21 Python
哪些是python中web开发框架
Jun 17 Python
python解决OpenCV在读取显示图片的时候闪退的问题
Feb 23 Python
Python机器学习应用之工业蒸汽数据分析篇详解
Jan 18 Python
Python使用华为API为图像设置多个锚点标签
Apr 12 Python
Django中在xadmin中集成DjangoUeditor过程详解
Jul 24 #Python
Django 权限认证(根据不同的用户,设置不同的显示和访问权限)
Jul 24 #Python
Django 创建/删除用户的示例代码
Jul 24 #Python
python3.6+django2.0+mysql搭建网站过程详解
Jul 24 #Python
简单了解python 邮件模块的使用方法
Jul 24 #Python
python 根据字典的键值进行排序的方法
Jul 24 #Python
如何使用Flask-Migrate拓展数据库表结构
Jul 24 #Python
You might like
php中数据的批量导入(csv文件)
2006/10/09 PHP
php实现首页链接查询 友情链接检查的代码
2010/01/05 PHP
通过PHP的内置函数,通过DES算法对数据加密和解密
2012/06/21 PHP
[原创]php常用字符串输出方法分析(echo,print,printf及sprintf)
2016/07/09 PHP
THINKPHP-Apache服务器中使用Alias虚拟目录URL重写 隐藏index.php
2021/03/09 PHP
会自动逐行上升的文本框
2006/06/30 Javascript
jquery 插件 任意位置浮动固定层
2008/12/25 Javascript
jQuery 名称冲突的解决方法
2011/04/08 Javascript
使用JSLint提高JS代码质量方法分享
2013/12/16 Javascript
JavaScript二维数组实现的省市联动菜单
2014/05/08 Javascript
javascript实时显示北京时间的方法
2015/03/12 Javascript
jQuery+HTML5实现手机摇一摇换衣特效
2015/06/05 Javascript
js简单设置与使用cookie的方法
2016/01/22 Javascript
jquery实现列表上下移动功能
2016/02/25 Javascript
AngularJs Javascript MVC 框架
2016/06/20 Javascript
javascript实现的图片预览功能
2017/03/25 Javascript
详解angularjs的数组传参方式的简单实现
2017/07/28 Javascript
详解webpack的配置文件entry与output
2017/08/21 Javascript
对numpy和pandas中数组的合并和拆分详解
2018/04/11 Python
python 实现绘制整齐的表格
2019/11/18 Python
双向RNN:bidirectional_dynamic_rnn()函数的使用详解
2020/01/20 Python
Python pip安装模块提示错误解决方案
2020/05/22 Python
python中numpy数组与list相互转换实例方法
2021/01/29 Python
French Connection官网:女装、男装及家居用品
2019/03/18 全球购物
护士岗位职责
2014/02/16 职场文书
社会调查研究计划书
2014/05/01 职场文书
专家推荐信怎么写
2015/03/25 职场文书
2015年大学班主任工作总结
2015/04/30 职场文书
不同意离婚代理词
2015/05/23 职场文书
统招统分证明
2015/06/23 职场文书
《夹竹桃》教学反思
2016/02/23 职场文书
小学三年级语文教学反思
2016/03/03 职场文书
62句有关感恩节文案(推荐收藏)
2019/11/28 职场文书
Python实现排序方法常见的四种
2021/07/15 Python
UNION CREATIVE《Re:从零开始的异世界生活》雷姆手办
2022/03/20 日漫
我的收音机情缘
2022/04/05 无线电