Python中__new__与__init__的执行顺序及核心区别详解
本文详细解析Python中__new__与__init__两个特殊方法的执行顺序与核心区别。__new__作为类级别的静态方法,负责创建并返回实例对象;__init__作为实例级别的方法,负责初始化已创建的实例。通过继承int等不可变类的示例,展示如何重载__new__实现自定义实例化逻辑,帮助开发者理解对象创建机制。
相同点
两者均为Python面向对象体系中的内置函数。其中,__new__的使用频率相对较低,而__init__则是日常开发中更为常见的函数。
不同点
__new__在实例创建之前被调用,其核心任务是创建实例对象并返回该实例,因此它属于静态方法。相比之下,__init__在实例对象创建完成后被调用,主要用于设置对象属性的初始值,通常用于初始化类实例,属于实例方法。
简而言之:__new__先执行,__init__后执行。__new__的返回值(即创建的实例)会作为第一个参数传递给__init__方法,随后__init__利用该实例进行参数设置。

===》》》
补充说明
1、只有继承自object的新式类才具备__new__方法。
2、__new__至少需要包含一个参数cls,代表当前类。在实例化过程中,Python解释器会自动识别并传入该参数。
3、__new__必须包含返回值,即返回实例化后的实例。在自定义实现__new__时需特别注意:可以返回通过super(当前类名, cls)调用的父类__new__产生的实例,或者直接返回由object的__new__产生的实例。
4、__init__包含一个参数self,该参数即为__new__返回的实例。__init__在__new__的基础上完成其他初始化动作,且__init__不需要返回值。
5、如果__new__创建的是当前类的实例,系统会自动调用__init__函数。通过return语句中调用的__new__函数的第一个参数cls来确保是当前类实例;若返回的是其他类的类名,则实际创建并返回的是其他类的实例,此时不会调用当前类的__init__函数,也不会调用其他类的__init__函数。
6、在定义子类时,若未重新定义__new__(),Python默认会调用该类的直接父类的__new__()方法来构造该类的实例。如果该类的父类也未重写__new__(),则规则将一直追溯至object的__new__()方法,因为object是所有新式类的基类。
7、若子类中重写了__new__()方法,你可以自由选择任意其他新式类(必须为新式类,因为所有新式类都拥有__new__(),而经典类没有)的__new__()方法来制造实例。这包括该新式类的所有前代类和后代类,只要不造成递归死循环即可。注意:绝对不能调用自己的__new__,否则会导致死循环。
8、对于子类的__init__,其调用规则与__new__一致。若需同时调用子类和父类的__init__函数,可在子类的__init__函数中显式加入对父类__init__函数的调用。
9、在实际使用中,建议优先使用__init__函数,尽量避免自定义__new__函数,因为两者在继承派生时的特性存在显著差异。
10、可以将类比作制造商:__new__方法相当于前期的原材料采购环节,而__init__方法则是在拥有原材料的基础上,进行加工和初始化的商品制作环节。
__init__方法

__new__方法
__new__方法接受的参数虽然与__init__相似,但__init__是在类实例创建之后调用,而__new__方法正是用于创建该类的实例。
===》
具体的执行逻辑如下:
1. p = Person(name, age)
2. 首先执行使用name和age参数来调用Person类的__new__方法,该__new__方法会返回Person类的一个实例(通常情况下采用 super(Persion, cls).__new__(cls, ... ...) 的方式),
3. 随后利用该实例来调用类的__init__方法,上一步中__new__产生的实例即为__init__中的self。
因此,__init__和__new__最主要的区别在于:
1.__init__通常用于初始化一个新实例,控制初始化过程,例如添加属性或执行额外操作,发生在类实例创建完成之后。它是实例级别的方法。
2.__new__通常用于控制生成一个新实例的过程。它是类级别的方法。
__new__的作用
根据Python官方文档,__new__方法主要用于当你继承一些不可变的class(如int、str、tuple)时,提供自定义这些类实例化过程的途径。此外,它还用于实现自定义的metaclass。
首先来看第一个功能,我们可以以int为例进行具体说明:
假如我们需要一个永远为正数的整数类型,通过集成int,我们可能会写出如下代码。

但运行后会发现,结果并非预期,我们仍然得到了-3。这是因为对于int这类不可变对象,只有重载其__new__方法才能起到自定义作用。
这是修改后的代码:

通过重载__new__方法,我们成功实现了所需功能。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













