源码内容:

    def __init_subclass__(self, *args, **kwargs): # real signature unknown"""This method is called when a class is subclassed.The default implementation does nothing. It may beoverridden to extend subclasses."""pass

先看下面代码执行的效果:

示例代码1:

class Test(object):def __init_subclass__(cls, **kwargs):print("__init_subclass__", cls, kwargs)class A(Test, name="张三", age=16):pass"""
代码运行直接输出下面的结果:__init_subclass__ <class '__main__.A'> {'name': '张三', 'age': 16}
"""

运行结果:

        上面代码中定义了一个Test类,然后让A这个类继承它。发现还没有实例化,而是在创建类的时候就有输出结果了。

对于一个类,如果这个类被作为父类继承,那么会触发其内部的__init_subclass__方法,这里的Test被A继承,那么Test中的__init_subclass__就会被触发。而且看到,里面的cls,就是定义的字类A,也就是继承它的类,**kwargs,就是额外传递的参数。但是发现,第一个参数不是self,而是cls,而且这个cls还不是Test,而是继承它的类。其实这个方法是隐式的被classmethod装饰了。

当多个类同时继承Test父类时,示例代码如下:

class Test(object):def __init_subclass__(cls, **kwargs):print("__init_subclass__", cls, kwargs)class A(Test, name="张三", age=16):passclass B(Test, name="李四", age=26):pass"""
代码运行直接输出下面的结果:__init_subclass__ <class '__main__.A'> {'name': '张三', 'age': 16}__init_subclass__ <class '__main__.B'> {'name': '李四', 'age': 26}
"""

运行结果:

        有时候想控制类的生成过程,怎么办呢?显然可以通过元类的的方式,但是如果场景比较简单,也没必要使用元类。直接使用__init_subclass__即可

示例代码2:

class Test(object):def __init_subclass__(cls, **kwargs):for k, v in kwargs.items():type.__setattr__(cls, k, v)class A(Test, name="张三", age=16):passprint(A.name)  # 张三
print(A.age)  # 16

运行结果:

        可以看到,在不使用元类的情况下,通过__init_subclass__实现了类的自定义过程。当然这比较简单,也可以实现更复杂的逻辑,在某些场景下,可以替代元类。

示例代码3:

class TestBase(object):def __init_subclass__(cls, default_name, **kwargs):super().__init_subclass__(**kwargs)cls.default_name = default_nameprint(cls.default_name)class Test(TestBase, default_name="张三"):passclass NewTest(Test, default_name="李四"):pass

运行结果:

在上述代码3中,当有子类继承了 TestBase类时,那么 __init_subclass__ 就会调用。内容也很简单,父类 TestBase为它的所有子类都设置了default_name 属性。

__init_subclass__ 就像是个钩子函数,当子类定义之后触发。

默认实现 object.__init_subclass__ 不执行任何操作。但默认实现不能传递任何参数,否则报错。
        值得注意的是,示例中的 __init_subclass__ 第一个参数是 cls 而不是常见的 self 。这是因为这个方法隐式地被 @classmethod 装饰。

__init_subclass__() 是钩子函数,它解决了如何让父类知道被继承的问题。钩子中能改变类的行为,而不必求助与元类或类装饰器。钩子用起来也更简单且容易理解。

示例代码4:

# defining a SuperClass
class SuperClass(object):# defining __init_subclass__ methoddef __init_subclass__(cls, **kwargs):cls.default_name = "Inherited Class"# defining a SubClass
class SubClass(SuperClass):# an attribute of SubClassdefault_name = "SubClass"print(default_name)subclass = SubClass()
print(subclass.default_name)

运行结果:

在上面示例代码4中,有 2 个类(即 SuperClass() 和 SubClass()),其中,SubClass() 继承自 SuperClass(),default_name是 SubClass()的一个属性。
        属性default_name的值由 SuperClass()使用__init_subclass__方法更改。cls指的是继承的子类。给新类的关键字参数(**kwargs)被传递给父类__init_subclass__。为了与使用 __init_subclass__ 的其他子类兼容,应该取出所需的关键字参数并将其他的传递给基类(超类)。

这个__init_subclass__方法看起来很像 Decorator类。但是,如果类装饰器仅影响它们所应用的特定类,则__init_subclass__仅适用于定义该方法的类的未来子类。这意味着可以更改/定义从超类继承的任何新类的行为。

示例代码5:

# defining a SuperClass
class SuperClass(object):# defining __init_subclass__ methoddef __init_subclass__(cls, **kwargs):cls.default_name = "Inherited Class"# defining a SubClass
class SubClass(SuperClass):# an attribute of SubClassdefault_name = "SubClass"print(default_name)default_name2 = "SubClass2"print(default_name2)subclass = SubClass()
print(subclass.default_name)
print(subclass.default_name2)

运行结果:

示例代码6:

# defining a SuperClass
class SuperClass(object):def __init_subclass__(cls, default_name, **kwargs):cls.default_name = default_name# defining a subclass
class SubClass1(SuperClass, default_name="SubClass1"):pass# defining another subclass
class SubClass2(SuperClass, default_name="SubClass2"):default_name = "InheritedClass"# references for subclasses
subClass1 = SubClass1()
subClass2 = SubClass2()print(subClass1.default_name)
print(subClass2.default_name)

运行结果:

有示例代码6中可以得出结论,__init_subclass__ 方法用于改变将来可能创建的子类的行为。

示例代码7:

class Base(object):_sub_class = {}_base_class_name = 'base_class'def __init_subclass__(cls, **kwargs):super().__init_subclass__()cls._sub_class[cls._base_class_name] = cls# cls._sub_class[cls._base_class_name] = cls()print(cls._sub_class)print(cls._base_class_name)print("*" * 100)class SubClass(Base):passobj = SubClass()
print(obj)
print(obj._sub_class)
print(obj._base_class_name)

运行结果:

示例代码8:

class Base(object):_sub_class = {}_base_class_name = 'base_class'def __init_subclass__(cls, **kwargs):super().__init_subclass__()cls._sub_class[cls._base_class_name] = cls# cls._sub_class[cls._base_class_name] = cls()print(cls._sub_class)print(cls._base_class_name)cls._base_class_name = 'I am base!'print(cls._base_class_name)print("*" * 100)class SubClass(Base):passobj = SubClass()
print(obj)
print(obj._sub_class)
print(obj._base_class_name)

运行结果:

python中__init_subclass__方法用法详解相关推荐

  1. python中.format()方法用法详解

    format语法格式: str.format()         str是指字符串实例对象,常用格式为' '.format() def format(self, *args, **kwargs): # ...

  2. python中的super用法详解_【Python】【类】super用法详解

    一.问题的发现与提出 在Python类的方法(method)中,要调用父类的某个方法,在Python 2.2以前,通常的写法如代码段1: 代码段1: class A: def __init__(sel ...

  3. python中的super用法详解_Python中super函数用法实例分析

    本文实例讲述了python中super函数用法.分享给大家供大家参考,具体如下: 这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简 ...

  4. python classmethod_对Python中的@classmethod用法详解

    在Python面向对象编程中的类构建中,有时候会遇到@classmethod的用法. 总感觉有这种特殊性说明的用法都是高级用法,在我这个层级的水平中一般是用不到的. 不过还是好奇去查了一下. 大致可以 ...

  5. python中setattr()函数用法详解

    setattr() 函数对应函数 getattr(),用于设置属性值,该属性不一定是存在的. getattr()用法详见博文:python中getattr()函数用法详解_IT之一小佬的博客-CSDN ...

  6. Python中self的用法详解(链接传送)

    Python中的self是什么意思? Python新手,今天看了一篇详细易懂的self用法介绍,感觉开了些窍,这里附上链接,以方便复习. Python中self用法详解(转载自CLHugh)

  7. php中sisson用法,thinkPHP中session()方法用法详解

    本文实例讲述了thinkPHP中session()方法用法.分享给大家供大家参考,具体如下: 系统提供了Session管理和操作的完善支持,全部操作可以通过一个内置的session函数完成. 用法 s ...

  8. Python中import语句用法详解

    一. 什么是模块(module)? 在实际应用中,有时程序所要实现功能比较复杂,代码量也很大.若把所有的代码都存储在一个文件中,则不利于代码的复用和维护.一种更好的方式是将实现不同功能的代码分拆到多个 ...

  9. python中dns库用法详解(DNS处理模块)

    dnspython是python 实现的一个dns场景的工具包. dnspython(http://www.dnspython.org/)是Python实现的一个DNS工具包,它支持几乎所有的记录类型 ...

最新文章

  1. Sass函数:Sass Maps的函数-map-has-key($map,$key)
  2. Angular的Zone-Evergreen在SAP Spartacus中的应用
  3. JAVA程序设计计时器代码_Java中的定时器Timer使用示例代码详解
  4. 笑郭网络验证3.8研究笔记(内有视频教程)
  5. 质性研究工具_质性研究【001】
  6. c语言程序设计的日志,C语言程序设计教学日志.docx
  7. 华为手机_text是什么文件_华为学习文档资料
  8. Linux netfilter源码分析(7)
  9. 在sqlServer中把数据导出为insert脚本
  10. java jar killed_我的Java应用程序被OOMKilled了,原因竟是这样?
  11. 有20万3年不用,怎样理财呢?
  12. python调用r语言加载包错误_Python中调用R语言包指南.docx
  13. 什么样的 python 可以可谓专业 PyPI 项目?刚刚学到三个概念:pep8、Sphinx、pytest与GitHub Action的集成
  14. 学习.NET好书推荐
  15. 如何修改Tomcat的默认主页
  16. 普通PC通过USB转485串口 ModBus-RTU通信协议控制伺服电机
  17. 【兴趣】QQ音乐VS网易云音乐竞品分析
  18. 蓝桥杯Python初级组测试题之Turtle画图2
  19. 原型软件--Balsamiq Mockups
  20. 【照片动态特效系列】旋转吧,照片!

热门文章

  1. 关于第十三届蓝桥杯大赛校内选拔赛的通知
  2. excel的简单操作
  3. 【报告分享】2021年中国新能源汽车行业洞察-Mob研究院(附下载)
  4. Android客户端与PC服务器实现Socket通信
  5. JDO与JPA哪个更好?
  6. hxxp://www.hao923.com.cn/劫持浏览器
  7. mac本更新chromedriver版本
  8. 5G注册流程分级详解Step4-8
  9. 南京申瓯SOC1000-UC IPPBX为中小企业提供电话系统解决方案
  10. 饿了么为啥给你推荐这个?本地生活搜索算法解密