小猿会从最基础的面试题开始,每天一题。如果参考答案不够好,或者有错误的话,麻烦大家可以在留言区给出自己的意见和讨论,大家是要一起学习的 。
废话不多说,开始今天的题目:
问:说说Python中的__new__和__init__的区别?
答:在Python中__new__和__init__具有不同的功能。并且对于Python的新类和旧类而言功能也不同。
__new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例对象,是个静态方法。
__init__是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值,通常用在初始化一个类实例的时候。是一个实例方法。
主要区别在于:__new__是用来创造一个类的实例的,而__init__是用来初始化一个实例的。
下文来源于:
Python的新类和旧类
Python中的类分为新类和旧类。旧类是Python3之前的类,旧类并不是默认继承object
类,而是继承type
类。
Python2中的旧类如下面代码所示:
class oldStyleClass: # inherits from 'type' pass
Python2中定义一个新类:
class newStyleClass(object): # explicitly inherits from 'object' pass
在Python3中所有的类均默认继承object
,所以并不需要显式地指定object
为基类。
以object
为基类可以使得所定义的类具有新类所对应的方法(methods
)和属性(properties
)。
在下面的文章中我们会分别基于新类和旧类探讨__new__
和__init__
。
__new__
和__init__
参数的不同
__new__
所接收的第一个参数是cls
,而__init__
所接收的第一个参数是self
。这是因为当我们调用__new__
的时候,该类的实例还并不存在(也就是self
所引用的对象还不存在),所以需要接收一个类作为参数,从而产生一个实例。而当我们调用__init__
的时候,实例已经存在,因此__init__
接受self
作为第一个参数并对该实例进行必要的初始化操作。这也意味着__init__
是在__new__
之后被调用的。
Python旧类中的__new__
和__init__
Python的旧类中实际上并没有__new__
方法。因为旧类中的__init__
实际上起构造器的作用。所以如果我们定义如下旧类:
class oldStyleClass: def __new__(cls): print("__new__ is called") # this line will never get called during construction oldStyleClass()
程序输出结果如下:
<__main__.oldStyleClass instance at 0x109c45518>
可见创建及初始化对象的过程并没有调用__new__
。实际上,除非显式调用:oldStyleClass.__new__(oldStyleClass)
,该类中的__new__
方法中的内容永远不会被调用。因为旧类构造实例并不会调用__new__
方法。
但如果我们重载__init__
方法:
class oldStyleClass: def __init__(self): print("__init__ is called") oldStyleClass()
该程序将会输出
__init__ is called <__main__.oldStyleClass instance at 0x1091992d8>
如果我们在__init__
中加上return
语句,将会导致TypeError: __init__() should return None
的错误。
class oldStyleClass: def __init__(self): return 29 oldStyleClass()
程序结果如下:
TypeError: __init__() should return None
这意味着对于Python的旧类而言,我们无法控制__init__
函数的返回值。