详解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 itertools模块详解
May 09 Python
使用相同的Apache实例来运行Django和Media文件
Jul 22 Python
python 数据清洗之数据合并、转换、过滤、排序
Feb 12 Python
python初学之用户登录的实现过程(实例讲解)
Dec 23 Python
Python+OpenCV实现车牌字符分割和识别
Mar 31 Python
python 自动批量打开网页的示例
Feb 21 Python
python装饰器简介---这一篇也许就够了(推荐)
Apr 01 Python
django数据关系一对多、多对多模型、自关联的建立
Jul 24 Python
Django使用中间件解决前后端同源策略问题
Sep 02 Python
Python脚本实现监听服务器的思路代码详解
May 28 Python
Python中zipfile压缩文件模块的基本使用教程
Jun 14 Python
零基础小白多久能学会python
Jun 22 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中Session的概念
2006/10/09 PHP
smarty模板嵌套之include与fetch性能测试
2010/12/05 PHP
浅析SVN常见问题及解决方法
2013/06/21 PHP
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2611816 bytes)
2014/11/08 PHP
laravel 解决Eloquent ORM的save方法无法插入数据的问题
2019/10/21 PHP
extjs之去除s.gif的影响
2010/12/25 Javascript
基于JQuery 的消息提示框效果代码
2011/07/31 Javascript
js 使用form表单select类实现级联菜单效果
2012/12/19 Javascript
单击按钮显示隐藏子菜单经典案例
2013/01/04 Javascript
弹出窗口并且此窗口带有半透明的遮罩层效果
2014/03/13 Javascript
用jquery写的菜单从左往右滑动出现
2014/04/11 Javascript
jquery 实现input输入什么div图层显示什么
2014/06/15 Javascript
JS获取当前网页大小以及屏幕分辨率等
2014/09/05 Javascript
jQuery中wrapInner()方法用法实例
2015/01/16 Javascript
JavaScript获取文本框内选中文本的方法
2015/02/20 Javascript
javascript实现3D切换焦点图
2015/10/16 Javascript
vue2利用Bus.js如何实现非父子组件通信详解
2017/08/25 Javascript
一篇文章介绍redux、react-redux、redux-saga总结
2019/05/23 Javascript
JavaScript中将值转换为字符串的五种方法总结
2019/06/06 Javascript
手把手教你 CKEDITOR 4 实现Dialog 内嵌 IFrame操作详解
2019/06/18 Javascript
js图数据结构处理 迪杰斯特拉算法代码实例
2019/09/11 Javascript
[49:13]DOTA2上海特级锦标赛C组资格赛#1 OG VS LGD第一局
2016/02/27 DOTA
[48:32]VGJ.T vs Fnatic 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
轻松掌握python设计模式之策略模式
2016/11/18 Python
python画图的函数用法以及技巧
2019/06/28 Python
对django的User模型和四种扩展/重写方法小结
2019/08/17 Python
python获取整个网页源码的方法
2020/08/03 Python
美国顶尖折扣时尚购物网:Bluefly
2016/08/28 全球购物
《最佳路径》教学反思
2014/04/13 职场文书
优秀研究生主要事迹
2014/06/03 职场文书
向国旗敬礼活动总结范文2014
2014/09/27 职场文书
布达拉宫导游词
2015/02/02 职场文书
《认识年月日》教学反思
2016/02/19 职场文书
MySQL删除和插入数据很慢的问题解决
2021/06/03 MySQL
vue-router中hash模式与history模式的区别
2021/06/23 Vue.js
SONY AN-LP1 短波有源天线放大器图
2022/04/05 无线电