在Python中,__new__和__init__是对象创建与初始化的关键方法,两者在功能、调用顺序和返回值上有显著区别。以下是详细分析:
1. 核心区别
(1)作用不同
new:
负责创建对象实例,分配内存空间,并返回新创建的实例。它是静态方法,直接操作类级别的行为,例如控制实例化过程或返回其他类型的对象。
init:
负责初始化对象属性,在实例已创建后设置初始状态。它是实例方法,通过self参数操作对象属性。
一句话简单概括:__new__方法创建并返回实例,__init__初始化实例
(2)调用顺序
- __new__先于__init__调用。
执行顺序,先执行__new__方法,再执行__init__方法
当通过类名实例化对象时,首先调用__new__方法创建实例,然后将该实例作为__init__的self参数进行初始化。
class MyClass:
def __init__(self):
print("__init__ running")
def __new__(cls):
print("__new__ running")
return super().__new__(cls)
instance= MyClass()
#__new__ running
#__init__ running
(3)参数与返回值
关键点:
- 若__new__未正确返回实例,__init__不会执行。
- __new__可返回其他类的实例(如返回list对象),此时__init__可能不会被调用。
class MyClass:
def __new__(cls):
print("__new__ running")
instance = super().__new__(cls)
# return instance
def __init__(self):
print("__init__ running")
instance= MyClass()
# __new__ running
(4)new__方法构造一个类实例,并将该实例传递给自身的__init()方法,即__init__()方法的self参数。
class MyClass:
def __new__(cls):
print("__new__ running")
instance = super().__new__(cls)
print(instance)
print(type(instance))
print(id(instance))
print("\n")
return instance
def __init__(self):
print("__init__ running")
print(self)
print(type(self))
print(id(self))
instance= MyClass()
# __new__ running
# <__main__.MyClass object at 0x000001C906EFCBB0>
# <class '__main__.MyClass'>
# 1962916432816
# __init__ running
# <__main__.MyClass object at 0x000001C906EFCBB0>
# <class '__main__.MyClass'>
# 1962916432816
(5)如果重写__new__方法,除了cls参数外,还需保持和__init__的其他入参一致
class MyClass:
def __new__(cls):
print("__new__ running")
instance = super().__new__(cls)
return instance
def __init__(self,name,age):
print("__init__ running")
self.name =name
self.age = age
instance= MyClass('YANG',99)
#Traceback (most recent call last):
# File "xxx.py", line 14, in <module>
# instance= MyClass('YANG',99)
#TypeError: __new__() takes 1 positional argument but 3 were given
正确应该这样写:
class MyClass:
def __new__(cls,name,age):
print("__new__ running")
instance = super().__new__(cls)
return instance
def __init__(self,name,age):
print("__init__ running")
self.name =name
self.age = age
instance= MyClass('YANG',99)
或者,推荐这样写:
class MyClass:
def __new__(cls,*args,**kwargs):
print("__new__ running")
instance = super().__new__(cls)
return instance
def __init__(self,name,age):
print("__init__ running")
self.name =name
self.age = age
instance= MyClass('YANG',99)
2. __new__的返回值
- 必须返回一个对象实例:
通常通过super.new(cls)调用父类方法创建实例,并返回该实例。若返回非对象类型(如None或基本数据类型),则__init__不会执行。
特殊场景:
- 单例模式:通过判断实例是否存在,决定是否创建新实例。
- 工厂模式:根据参数返回不同子类的实例。
- 继承不可变类型:如自定义int子类时,需在__new__中固定值。
3. 典型应用场景
1.单例模式
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super.__new__(cls)
return cls._instance
通过__new__确保全局仅有一个实例。
2.不可变类型继承
class PositiveInt(int):
def __new__(cls, value):
return super.__new__(cls, abs(value)) # 强制值为正数
在__new__中修改参数以控制对象创建。
3.工厂模式
通过__new__根据参数返回不同子类实例,实现动态对象生成。
# 可以应用到不同数据库的连接上
class Shape:
def __new__(cls, type_, *args, **kwargs):
if type_ == "circle":
instance = super.__new__(Circle)
elif type_ == "square":
instance = super.__new__(Square)
else:
raise ValueError(f"Unknown shape type: {type_}")
# 初始化实例(可选)
instance.type = type_
return instance
class Circle(Shape):
def __init__(self, radius):
self radius = radius
print(f"Circle created with radius {radius}")
class Square(Shape):
def __init__(self, side):
self侧长 = side
print(f"Square created with side {side}")
# 使用工厂模式创建对象
circle = Shape("circle", radius=5) # 输出: Circle created with radius 5
square = Shape("square", side=4) # 输出: Square created with side 4
print isinstance(circle, Circle) # 输出: True
print isinstance(square, Square) # 输出: True
实现原理:
- new 方法:在基类 Shape 中重写 new,根据传入的 type_ 参数决定创建哪个子类实例。
- 动态实例化:通过 super.new(子类) 直接调用子类的构造方法,确保对象类型正确。
- 参数传递:*args 和 **kwargs 会自动传递给子类的 init 方法。
优点:
- 集中控制对象创建:所有对象创建逻辑在基类中统一管理。
- 类型安全:通过 type_ 参数限制可创建的类型,避免非法实例。
- 扩展性强:新增子类时只需修改 new 中的条件判断,无需修改调用代码。
对比传统工厂模式:
传统工厂模式通常通过类方法(如 create)实现,而 new 方法直接拦截实例化过程,更符合Python的面向对象特性。
4. 总结对比表
通过理解两者的分工,可以更灵活地控制对象生命周期。通常情况下,仅需重写__init__进行初始化;而__new__适用于需要深度定制实例化逻辑的场景。