Python面试题系列之12 __init__和__new__区别?

Python面试题系列之12: initnew区别?

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

  1. __new__是一个类方法,它返回的是一个实例
  2. __init__是一个实例方法,它什么都不返回
  3. 只有在__new__返回一个新创建属于该类的实例时,当前类的__init__才会被调用。

后记

在理解__init____new__的区别之后,思考下__new__还有哪些应用场景呢?好了,以上就是本篇全部内容。

备注:本篇首发于知识星球「人人都是Pythonista」。


文章作者: &娴敲棋子&
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 &娴敲棋子& !
评论
  目录