Python中的__new__和__init__的区别
2017-06-20 16:35
537 查看
摘要
本文讨论了Python中__init__和
__new__方法。
__new__和
__init__具有不同的功能。并且对于Python的新类和旧类而言功能也不同。
__new__
和__init__
功能上的区别
__new__和
__init__的主要区别在于:
__new__是用来创造一个类的实例的(constructor),而
__init__是用来初始化一个实例的(initializer)。
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__函数的返回值。
Python新类中的__new__
和__init__
Python的新类允许用户重载__new__和
__init__方法,且这两个方法具有不同的作用。
__new__作为构造器,起创建一个类实例的作用。而
__init__作为初始化器,起初始化一个已被创建的实例的作用。
如下面代码是所示:
class newStyleClass(object): # In Python2, we need to specify the object as the base. # In Python3 it's default. def __new__(cls): print("__new__ is called") return super(newStyleClass, cls).__new__(cls) def __init__(self): print("__init__ is called") print("self is: ", self) newStyleClass()
结果如下:
__new__ is called __init__ is called self is: <__main__.newStyleClass at 0x109290890> <__main__.newStyleClass at 0x109290890>
创建类实例并初始化的过程中
__new__和
__init__被调用的顺序也能从上面代码的输出结果中看出:
__new__函数首先被调用,构造了一个
newStyleClass的实例,接着
__init__函数在
__new__函数返回一个实例的时候被调用,并且这个实例作为
self参数被传入了
__init__函数。
这里需要注意的是,如果
__new__函数返回一个已经存在的实例(不论是哪个类的),
__init__不会被调用。如下面代码所示:
obj = 12 # obj can be an object from any class, even object.__new__(object) class returnExistedObj(object): def __new__(cls): print("__new__ is called") return obj def __init(self): print("__init__ is called") returnExistedObj()
执行结果如下:
__new__ is called 12
同时另一个需要注意的点是:
如果我们在
__new__函数中不返回任何对象,则
__init__函数也不会被调用。
如下面代码所示:
class notReturnObj(object): def __new__(cls): print("__new__ is called") def __init__(self): print("__init__ is called") print(notReturnObj())
执行结果如下:
__new__ is called None
可见如果
__new__函数不返回对象的话,不会有任何对象被创建,
__init__函数也不会被调用来初始化对象。
总结几个点
__init__不能有返回值
__new__函数直接上可以返回别的类的实例。如上面例子中的
returnExistedObj类的
__new__函数返回了一个
int值。
只有在
__new__返回一个新创建属于该类的实例时当前类的
__init__才会被调用。
如下面例子所示:
class sample(object): def __str__(self): print("sample") class example(object): def __new__(cls): print("__new__ is called") return sample() def __init__(self): print("__init__ is called") example()
输出结果为:
__new__ is called sample
相关文章推荐
- Python中__init__和__new__的区别详解
- python __init__和__new__之间的区别
- 【python】__new__和__init__的区别
- Python的__new__与__init__区别
- python中__new__和__init__的区别
- Python中的__init__方法与__new__方法的区别
- Python中__init__和__new__的区别详解
- Python __init__与__new__区别
- Python中__new__与__init__方法的区别详解
- Python中__new__与__init__方法的区别详解
- 【python】__new__和__init__区别
- 关于python中__init__()和__new__()的区别
- Python中__init__和__new__的区别详解
- Python中__new__与__init__方法的区别详解
- Python中__init__和__new__的区别详解
- python __init__和__new__之间的区别
- python中的__new__方法与__init__方法区别与调用;通过使用__new__实现单例模式
- python的__new__和__init__函数的区别
- Python基础(十) __init__与__new__区别
- python中__init__()方法和__new__()方法的区别