详解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操作mysql中文显示乱码的解决方法
Oct 11 Python
Python整型运算之布尔型、标准整型、长整型操作示例
Jul 21 Python
python实现媒体播放器功能
Feb 11 Python
Pycharm 设置自定义背景颜色的图文教程
May 23 Python
Python 查找list中的某个元素的所有的下标方法
Jun 27 Python
python实现趣味图片字符化
Apr 30 Python
python登录WeChat 实现自动回复实例详解
May 28 Python
Django处理Ajax发送的Get请求代码详解
Jul 29 Python
PyTorch使用cpu加载模型运算方式
Jan 13 Python
python实现删除列表中某个元素的3种方法
Jan 15 Python
python列表返回重复数据的下标
Feb 10 Python
Django操作cookie的实现
May 26 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支持页面回退的两种方法[转]
2007/02/14 PHP
php实现的SESSION类
2014/12/02 PHP
Zend Framework框架实现类似Google搜索分页效果
2016/11/25 PHP
精通Javascript系列之Javascript基础篇
2011/06/07 Javascript
javascript作用域和闭包使用详解
2014/04/25 Javascript
ActiveX控件与Javascript之间的交互示例
2014/06/04 Javascript
js获取对象、数组的实际长度,元素实际个数的实现代码
2016/06/08 Javascript
分享一个精简的vue.js 图片lazyload插件实例
2017/03/13 Javascript
Vue2.0表单校验组件vee-validate的使用详解
2017/05/02 Javascript
jQuery实现html table行Tr的复制、删除、计算功能
2017/07/10 jQuery
基于Vue实现图书管理功能
2017/10/17 Javascript
Vue.js用法详解
2017/11/13 Javascript
Vue的watch和computed方法的使用及区别介绍
2018/09/06 Javascript
bootstrap-paginator服务器端分页使用方法详解
2020/02/13 Javascript
原生js实现日历效果
2020/03/02 Javascript
vue 实现element-ui中的加载中状态
2020/11/11 Javascript
python 切片和range()用法说明
2013/03/24 Python
Python常用模块用法分析
2014/09/08 Python
Python sklearn KFold 生成交叉验证数据集的方法
2018/12/11 Python
python多进程重复加载的解决方式
2019/12/13 Python
如何利用Python给自己的头像加一个小国旗(小月饼)
2020/10/02 Python
CSS3实现网站商品展示效果图
2020/01/18 HTML / CSS
澳大利亚新奇小玩意网站:Yellow Octopus
2017/12/28 全球购物
阿联酋航空假期:Emirates Holidays
2018/03/20 全球购物
Lookfantastic香港官网:英国知名美妆购物网站
2018/06/19 全球购物
Lulu Guinness露露·吉尼斯官网:红唇包
2019/02/03 全球购物
CSS代码检查工具stylelint的使用方法详解
2021/03/27 HTML / CSS
上班上网检讨书
2014/01/29 职场文书
入党积极分子自我鉴定范文
2014/03/25 职场文书
2014国庆节商场促销活动策划方案
2014/09/16 职场文书
2015年师德师风承诺书
2015/01/22 职场文书
广告业务员岗位职责
2015/02/13 职场文书
2016应届毕业生自荐信范文
2016/01/28 职场文书
2016年领导干部廉政承诺书
2016/03/24 职场文书
Angular CLI发布路径的配置项浅析
2021/03/29 Javascript
Python接口自动化之文件上传/下载接口详解
2022/04/05 Python