详解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使用pyhook监控键盘并实现切换歌曲的功能
Jul 18 Python
Python中处理字符串之isalpha()方法的使用
May 18 Python
python实现网站的模拟登录
Jan 04 Python
python开发之list操作实例分析
Feb 22 Python
实例探究Python以并发方式编写高性能端口扫描器的方法
Jun 14 Python
Python计算两个日期相差天数的方法示例
May 23 Python
机器学习之KNN算法原理及Python实现方法详解
Jul 09 Python
Python嵌套式数据结构实例浅析
Mar 05 Python
python实现倒计时小工具
Jul 29 Python
python psutil监控进程实例
Dec 17 Python
Python的形参和实参使用方式
Dec 24 Python
基于pygame实现童年掌机打砖块游戏
Feb 25 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 pcntl_fork和pcntl_fork 的用法
2009/04/13 PHP
老版本PHP转义Json里的特殊字符的函数
2015/06/08 PHP
javascript小数计算出现近似值的解决办法
2010/02/06 Javascript
JavaScript打开word文档的实现代码(c#)
2012/04/16 Javascript
基于dom编程中 动态创建与删除元素的使用
2013/04/17 Javascript
JS画线(实例代码)
2013/11/20 Javascript
jquery实现可旋转可拖拽的文字效果代码
2016/01/27 Javascript
js正则表达式最长匹配(贪婪匹配)和最短匹配(懒惰匹配)用法分析
2016/12/27 Javascript
微信小程序scroll-view实现横向滚动和上拉加载示例
2017/03/06 Javascript
详解在vue-cli中使用路由
2017/09/25 Javascript
Vue进度条progressbar组件功能
2018/04/17 Javascript
JS中的变量作用域(console版)
2020/07/18 Javascript
原生JavaScript实现购物车
2021/01/10 Javascript
Python实现在线程里运行scrapy的方法
2015/04/07 Python
Python中super关键字用法实例分析
2015/05/28 Python
Python 3.x 新特性及10大变化
2015/06/12 Python
浅谈python多线程和队列管理shell程序
2015/08/04 Python
python机器学习实战之K均值聚类
2017/12/20 Python
python下解压缩zip文件并删除文件的实例
2018/04/24 Python
解决python nohup linux 后台运行输出的问题
2018/05/11 Python
解读python如何实现决策树算法
2018/10/11 Python
详解Python3 对象组合zip()和回退方式*zip
2019/05/15 Python
ansible动态Inventory主机清单配置遇到的坑
2020/01/19 Python
python爬虫开发之使用python爬虫库requests,urllib与今日头条搜索功能爬取搜索内容实例
2020/03/10 Python
基于Python爬取京东双十一商品价格曲线
2020/10/23 Python
美国体育用品商店:Paragon Sports
2017/10/08 全球购物
菲律宾票务网站:StubHub菲律宾
2018/04/21 全球购物
德国亚洲食品网上商店:asiafoodland.de
2019/12/28 全球购物
自考毕业生自我鉴定
2013/11/04 职场文书
财务经理岗位职责
2013/11/09 职场文书
分层教学实施方案
2014/03/19 职场文书
小班幼儿评语大全
2014/04/30 职场文书
2014年青年志愿者工作总结
2014/12/09 职场文书
MySQL插入数据与查询数据
2022/03/25 MySQL
浅谈Python中对象是如何被调用的
2022/04/06 Python
Java无向树分析 实现最小高度树
2022/04/09 Javascript