详解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下线程之间的共享和释放示例
May 04 Python
Python中利用sqrt()方法进行平方根计算的教程
May 15 Python
书单|人生苦短,你还不用python!
Dec 29 Python
python/sympy求解矩阵方程的方法
Nov 08 Python
Python实现的读取文件内容并写入其他文件操作示例
Apr 09 Python
Python使用统计函数绘制简单图形实例代码
May 15 Python
python增加图像对比度的方法
Jul 12 Python
python实现动态数组的示例代码
Jul 15 Python
对Django中内置的User模型实例详解
Aug 16 Python
python向图片里添加文字
Nov 26 Python
python 安装教程之Pycharm安装及配置字体主题,换行,自动更新
Mar 13 Python
django配置app中的静态文件步骤
Mar 27 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图片上传类带图片显示
2006/11/25 PHP
PHP中对用户身份认证实现两种方法
2011/06/04 PHP
php中用date函数获取当前时间有误的解决办法
2013/08/02 PHP
ThinkPHP学习笔记(一)ThinkPHP部署
2014/06/22 PHP
ThinkPHP自动填充实现无限级分类的方法
2014/08/22 PHP
htm调用JS代码
2007/03/15 Javascript
菜鸟javascript基础资料整理3 正则
2010/12/06 Javascript
通过jQuery源码学习javascript(二)
2012/12/27 Javascript
javascript使用isNaN()函数判断变量是否为数字
2013/09/21 Javascript
javascript实现的一个带下拉框功能的文本框
2014/05/08 Javascript
jQuery Validate插件自定义验证规则的方法
2016/12/27 Javascript
react-redux中connect()方法详细解析
2017/05/27 Javascript
使用JavaScript实现表格编辑器(实例讲解)
2017/08/02 Javascript
微信小程序实现点击按钮修改文字大小功能【附demo源码下载】
2017/12/06 Javascript
纯js+css实现仿移动端淘宝网站的弹出详情框功能
2019/12/29 Javascript
vue-video-player视频播放器使用配置详解
2020/10/23 Javascript
Python使用numpy模块创建数组操作示例
2018/06/20 Python
django 外键model的互相读取方法
2018/12/15 Python
详解Python3 基本数据类型
2019/04/19 Python
django组合搜索实现过程详解(附代码)
2019/08/06 Python
Python列表元素常见操作简单示例
2019/10/25 Python
Python3.7实现验证码登录方式代码实例
2020/02/14 Python
Python下载网易云歌单歌曲的示例代码
2020/08/12 Python
详解通过HTML5 Canvas实现图片的平移及旋转变化的方法
2016/03/22 HTML / CSS
高中自我鉴定范文
2013/11/03 职场文书
趣味活动策划方案
2014/02/08 职场文书
大学毕业感言200字
2014/03/09 职场文书
2014年度培训工作总结
2014/11/27 职场文书
怎样写离婚协议书
2015/01/26 职场文书
安全生产先进个人总结
2015/02/15 职场文书
运动员入场前导词
2015/07/20 职场文书
大学生自我鉴定怎么写
2019/05/07 职场文书
基于PyTorch实现一个简单的CNN图像分类器
2021/05/29 Python
详解php中流行的rpc框架
2021/05/29 PHP
python异常中else的实例用法
2021/06/15 Python
MySQL 如何设计统计数据表
2021/06/15 MySQL