# __new__和__init__有什么区别?
面试官问:"Python的__new__和__init__有什么区别?"
很多人只知道__init__是初始化方法,不知道还有__new__。真正要讲清楚的是:__new__负责创建对象并返回它,__init__负责初始化已经创建好的对象。 __new__先执行,返回值是对象本身;__init__后执行,在对象上添加属性,没有返回值。单例模式和自定义不可变类型时会重写__new__。
# 简要回答
__new__是类方法,负责创建对象。 它的第一个参数是cls(类本身),返回一个新创建的对象。如果__new__返回的是这个类的实例,Python会自动调用__init__初始化它。
__init__是实例方法,负责初始化对象。 它的第一个参数是self(刚创建好的对象),用于设置对象的初始属性。__init__不需要返回值,返回None。
调用顺序:obj = Class(args) → __new__(cls, args) → 返回对象 → __init__(self, args) → 返回给调用方。
# 详细回答
# 调用过程
当你写obj = MyClass(a, b)时,Python实际执行:
- 调用
MyClass.__new__(MyClass, a, b),创建对象。 - 如果
__new__返回的是MyClass的实例,**调用obj.__init__(a, b)**初始化。 - 返回初始化后的对象。
class Person:
def __new__(cls, name):
print(f"__new__ called with cls={cls}, name={name}")
instance = super().__new__(cls) # 调用object.__new__创建对象
print(f"__new__ returns {instance}")
return instance
def __init__(self, name):
print(f"__init__ called with self={self}, name={name}")
self.name = name
print("__init__ done")
p = Person("Alice")
# 输出:
# __new__ called with cls=<class '__main__.Person'>, name=Alice
# __new__ returns <__main__.Person object at 0x...>
# __init__ called with self=<__main__.Person object at 0x...>, name=Alice
# __init__ done
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 参数和返回值
__new__:
- 第一个参数是
cls,是类本身,不是对象。 - 必须返回一个对象。通常返回
super().__new__(cls)。 - 如果返回的不是当前类的实例,
__init__不会被调用。
__init__:
- 第一个参数是
self,是已经创建好的对象。 - 不应该有返回值(或返回
None)。如果返回其他值,Python会报错。 - 只负责设置属性,不负责创建对象。
class Test:
def __new__(cls):
print("Creating object")
return super().__new__(cls)
def __init__(self):
print("Initializing object")
self.value = 42
t = Test()
# 输出:
# Creating object
# Initializing object
2
3
4
5
6
7
8
9
10
11
12
13
# 为什么要分两个阶段
大多数情况下,你只需要重写__init__。但有些场景需要在对象创建时做特殊处理,这时就要重写__new__:
- 单例模式:确保类只创建一个实例。
- 继承不可变类型:
int、str、tuple等不可变对象在__init__时已经不能修改,必须在__new__阶段定制。 - 元类和特殊对象:控制对象的创建过程。

# 单例模式的实现
单例模式要求类只能创建一个实例。 通过重写__new__,检查是否已经创建过对象,如果有就返回已有对象:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
print("Creating the only instance")
cls._instance = super().__new__(cls)
else:
print("Returning existing instance")
return cls._instance
def __init__(self):
print("__init__ called")
s1 = Singleton() # Creating the only instance, __init__ called
s2 = Singleton() # Returning existing instance, __init__ called
print(s1 is s2) # True
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
注意:__init__每次都会被调用,即使返回的是同一个对象。如果不想重复初始化,需要加个标志位:
class Singleton:
_instance = None
_initialized = False
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not Singleton._initialized:
print("First init")
self.value = 42
Singleton._initialized = True
else:
print("Already initialized")
s1 = Singleton() # First init
s2 = Singleton() # Already initialized
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 继承不可变类型
不可变类型(int、str、tuple)的值在创建后不能改变,所以不能在__init__里修改。必须在__new__阶段定制:
class PositiveInt(int):
def __new__(cls, value):
if value < 0:
raise ValueError("Value must be positive")
return super().__new__(cls, value)
p = PositiveInt(10)
print(p) # 10
# p = PositiveInt(-5) # ValueError: Value must be positive
2
3
4
5
6
7
8
9
10
int.__new__需要接收值作为参数,所以我们传递value。创建后,这个对象的值就固定了,__init__无法修改。
同样的,自定义tuple子类时,也要在__new__里定制:
class NamedPoint(tuple):
def __new__(cls, x, y):
return super().__new__(cls, (x, y))
@property
def x(self):
return self[0]
@property
def y(self):
return self[1]
point = NamedPoint(3, 4)
print(point) # (3, 4)
print(point.x) # 3
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# __new__返回其他类型会怎样
如果__new__返回的不是当前类的实例,__init__不会被调用:
class A:
def __new__(cls):
print("A.__new__")
return "not an A instance"
def __init__(self):
print("A.__init__")
obj = A()
print(obj) # not an A instance
print(type(obj)) # <class 'str'>
# 注意:A.__init__没有被调用
2
3
4
5
6
7
8
9
10
11
12
# 知识拓展
Q1:为什么大多数时候只重写__init__?
因为object.__new__已经够用了,它会创建一个空对象。我们只需要在__init__里添加属性。只有需要控制对象创建过程时(单例、不可变类型、工厂模式),才需要重写__new__。
Q2:__new__是类方法还是静态方法?
它是个特殊方法,行为像类方法(第一个参数是cls),但不需要@classmethod装饰器。Python解释器会自动把类传给__new__。
Q3:能在__init__里返回一个值吗?
不能。__init__返回除None以外的值会报TypeError:
class Test:
def __init__(self):
return 42 # TypeError: __init__() should return None
2
3
Q4:super().__new__(cls)为什么要传cls?
因为object.__new__是个静态方法风格的特殊方法,需要知道创建哪个类的实例。传入cls,它会返回cls类型的对象。
Q5:多继承时__new__和__init__怎么调用?
按照MRO(方法解析顺序)调用。如果多个父类都重写了__new__或__init__,Python会按C3线性化的顺序调用。使用super()可以确保按MRO调用下一个类的方法。
评论
验证登录状态...