在 python 的面向对象编程中,__new__ 和 __init__ ,它们的职责、执行顺序和返回值完全不同。
__new__ 负责“出生”(创建实例),__init__ 负责“成长”(初始化属性)。
1. 核心区别对比表
| 特性 | __new__ | __init__ |
|---|---|---|
| 本质 | 静态方法(不需要 self ) | 实例方法 |
| 执行时机 | 最先执行,在实例创建之前 | 随后执行,在实例创建之后 |
| 主要职责 | 创建并返回一个新的实例对象 | 初始化已经创建的实例对象(赋值属性) |
| 第一个参数 | cls (类本身) | self (刚刚创建好的实例) |
| 返回值 | 必须返回一个实例对象 (通常由 super().__new__(cls) 返回) | 不需要返回值 (默认返回 none,若返回其他值会报错) |
| 使用场景 | 继承不可变类型、单例模式、控制实例创建过程 | 绝大多数常规的属性初始化 |
2. 执行流程详解
当你调用 myclass() 时,python 内部实际上做了以下步骤:
- 调用 __new__ 方法:
- 传入类 cls。
- 内存中分配空间,创建一个空的对象。
- 返回这个新对象。
- 如果 __new__ 返回的是该类的实例,python 会自动调用 __init__ 方法:
- 将 __new__ 返回的对象作为 self 传入。
- 执行初始化代码(如 self.name = ...)。
- __init__ 执行完毕,对象完全准备好。
3. 代码示例
场景 a:常规用法(只看init)
99% 的情况下,你只需要写 __init__,因为 __new__ 默认由 object 类处理好了。
class person:
def __init__(self, name):
print(f"2. __init__ 被调用,正在初始化: {name}")
self.name = name
p = person("alice")
# 输出:
# 2. __init__ 被调用,正在初始化: alice
场景 b:同时展示两者(看执行顺序)
class demo:
def __new__(cls, *args, **kwargs):
print("1. __new__ 被调用:负责创建实例")
# 必须调用父类的 __new__ 来真正创建对象,否则 __init__ 不会执行
instance = super().__new__(cls)
return instance
def __init__(self, value):
print("2. __init__ 被调用:负责初始化属性")
self.value = value
obj = demo(100)
print(f"最终对象值: {obj.value}")
输出结果:
1. __new__ 被调用:负责创建实例
2. __init__ 被调用:负责初始化属性
最终对象值: 100
4. 什么时候必须使用__new__?
既然 __init__ 这么好用,为什么还需要 __new__?主要在以下三种高级场景:
① 继承不可变类型(如int,str,tuple)
不可变类型一旦创建就不能修改。__init__ 是在对象创建后才运行的,此时对象已经定型,无法修改其值。必须在创建时(__new__)就确定值。
class myint(int):
# 想要强制让生成的整数都是偶数
def __new__(cls, value):
# 在创建之前就修改值
if value % 2 != 0:
value += 1
return super().__new__(cls, value)
# __init__ 在这里无法修改整数的值,因为 int 是不可变的
num = myint(5)
print(num) # 输出 6 (自动变成了偶数)
② 实现单例模式 (singleton)
确保一个类只有一个实例。可以在 __new__ 中判断实例是否已存在,如果存在则直接返回旧的,不再创建新的。
class singleton:
_instance = none
def __new__(cls, *args, **kwargs):
if not cls._instance:
print("创建新实例")
cls._instance = super().__new__(cls)
else:
print("返回已有实例")
return cls._instance
def __init__(self, name):
# 注意:即使返回旧实例,__init__ 仍会被调用,通常需要小心处理
self.name = name
s1 = singleton("a")
s2 = singleton("b")
print(s1 is s2) # true (是同一个对象)
print(s2.name) # "b" (注意:__init__ 再次运行覆盖了名字)
③ 控制实例的创建过程
比如根据参数决定返回哪个类的实例(工厂模式的一种变体),或者限制只能创建特定数量的实例。
class shape:
def __new__(cls, shape_type, *args, **kwargs):
if shape_type == "circle":
return super().__new__(circle)
elif shape_type == "square":
return super().__new__(square)
return super().__new__(cls)
class circle(shape):
pass
class square(shape):
pass
c = shape("circle")
print(type(c)) # <class '__main__.circle'>
总结
- 日常开发:只用 __init__。
- 需要修改不可变对象、控制实例生成(单例)、或动态返回不同子类实例时:使用 __new__。
- 记住:__new__ 是造物主(返回实例),__init__ 是装修工(修饰实例)。如果没有造物主造出房子,装修工是无活可干的。
到此这篇关于python面向对象中__new__和__init__区别的文章就介绍到这了,更多相关python __new__和__init__区别内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论