目录python
曾经我幼稚的觉得认识了python的__init__()方法就至关于认识了类构造器,结果,__new__()方法忽然出如今我眼前,让我忽然认识到原来__new__才是老大。为何这么说呢?spa
咱们首先得从__new__(cls[,...])的参数说提及,__new__方法的第一个参数是这个类,而其他的参数会在调用成功后所有传递给__init__方法初始化,这一会儿就看出了谁是老子谁是小子的关系。code
因此,__new__方法(第一个执行)先于__init__方法执行:对象
class A: pass class B(A): def __new__(cls): print("__new__方法被执行") return super().__new__(cls) def __init__(self): print("__init__方法被执行") b = B()
__new__方法被执行 __init__方法被执行
咱们比较两个方法的参数,能够发现__new__方法是传入类(cls),而__init__方法传入类的实例化对象(self),而有意思的是,__new__方法返回的值就是一个实例化对象(ps:若是__new__方法返回None,则__init__方法不会被执行,而且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法)。咱们能够这么理解它们之间的关系,__new__是开辟疆域的大将军,而__init__是在这片疆域上辛勤劳做的小老百姓,只有__new__执行完后,开辟好疆域后,__init__才能工做。继承
绝大多数状况下,咱们都不须要本身重写__new__方法,但在当继承一个不可变的类型(例如str类,int类等)时,它的特性就尤显重要了。咱们举下面这个例子:字符串
class CapStr(str): def __init__(self, string): string = string.upper() a = CapStr("I love China!") print(a)
I love China!
class CapStr(str): def __new__(cls, string): string = string.upper() return super().__new__(cls, string) a = CapStr("I love China!") print(a)
I LOVE CHINA!
咱们能够根据上面的理论能够这样分析,咱们知道字符串是不可改变的,因此第一个例子中,传入的字符串至关于已经被打下的疆域,而这块疆域除了将军其余谁也没法改变,__init__只能在这块领地上干瞪眼,此时这块疆域就是”I love China!“。而第二个例子中,__new__大将军从新去开辟了一块疆域,因此疆域上的内容也发生了变化,此时这块疆域变成了”I LOVE CHINA!“。string
小结:__new__和__init__想配合才是python中真正的类构造器。it