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」。