Python面试题系列之12: init和new区别?
Question
请简述下__init__
和__new__
区别?
知识点详解
在定义一个类时我们通常会使用__init__
的方法,在实例化对象的时候对属性进行设置。
class Star:
def __init__(self, name, id):
self.name = name;
self.id = id;
star = Star('人人都是Pythonista', 91155859)
但事实上,创建一个类的过程是分为两步的,首先是创建类的对象,第二步就是对类进行初始化。而这个__new__
正是用来创建类并返回这个类的实例,__init__
只是将传入的参数来初始化该实例。
class Star(object):
def __init__(self, name, id):
print('__init__ is called')
self.name = name
self.id = id
def __new__(cls, *args, **kwargs):
# 打印 __new__方法中的相关信息
print('__new__ is called')
print(args)
# 最后返回父类的方法
return super(Star, cls).__new__(cls)
if __name__ == '__main__':
star = Star('人人都是Pythonista', 91155859)
我们看看输出的结果:
__new__ is called
('人人都是Pythonista', 91155859)
__init__ is called
从上面代码的输出结果不难发现__new__
和__init__
被调用的顺序:__new__
函数首先被调用,构造了一个Star
的实例;接着__init__
函数在__new__
函数返回一个实例的时候被调用,并且这个实例作为self
参数被传入了__init__
函数。
除了功能上的差异外,两者的参数也是不同的。__new__
方式的第一个参数是cls
,而__init__
方式的第一个参数是self
。
当我们调用__new__
时,该类的实例还并不存在(换句话就是self所引用的对象还不存在),所以需要接收一个类作为参数,从而产生一个实例。而当我们在调用__init__
时,实例已经存在,此时__init__
用self
作为参数,就可以对该实例进行必要的初始化操作。
这里需要注意的是:如果__new__
返回一个已经存在的实例(无论是哪个类的),__init__
方法是不会被调用的。举个栗子:
Car = 'Tesla'
class Star(object):
def __new__(cls):
print("__new__ is called")
return Car
def __init__(self):
print("__init__ is called")
Star()
执行结果如下:
__new__ is called
Tesla
那如果我们在__new__
方法中不返回任何对象呢?举个栗子:
class Star(object):
def __new__(cls):
print("__new__ is called")
def __init__(self):
print("__init__ is called")
Star()
执行结果如下:
__new__ is called
None
由此可见,若__new__
方法不返回对象的话,此时就不会有任何对象被创建,__init__
方法同样也不会被调用(因为并没有对象来初始化)。
综上所述,只有在__new__
返回一个新创建属于该类的实例时,当前类的__init__
才会被调用。
还有一点需要注意的是:__new__
方法总是需要返回该类的一个实例,而__init__
不能返回除了None
的任何值。
class Star(object):
def __new__(cls):
print("__new__ is called")
return super(Star, cls).__new__(cls)
def __init__(self):
print("__init__ is called")
return '人人都是Pythonista'
Star()
执行之后,就会直接报错,提示
TypeError: __init__() should return None
Answer
__new__
是一个类方法,它返回的是一个实例__init__
是一个实例方法,它什么都不返回- 只有在
__new__
返回一个新创建属于该类的实例时,当前类的__init__
才会被调用。
后记
在理解__init__
和__new__
的区别之后,思考下__new__
还有哪些应用场景呢?好了,以上就是本篇全部内容。
备注:本篇首发于知识星球「人人都是Pythonista」。