Python 中的 __new__() 方法

我们首先得从 __new__(cls[,…]) 的参数说说起,__new__ 方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给 __init__ 方法初始化,这一下子就看出了谁是老子谁是小子的关系。

所以,__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__ 的返回值正是 __init__ 中 self。

我们可以看下面这个例子:

class CapStr(str):
    def __new__(cls, string):
        self_in_init = super().__new__(cls, string)
        print(id(self_in_init))
        return self_in_init
    def __init__(self,string):
        print(id(self))
 
a = CapStr("I love China!")
print(id(a))

执行结果为:

2691640428616
2691640428616
2691640428616

上面这段代码的内容很简单,在 __new__ 中打印一下返回值的 id,在 __init__ 中打印一下 self 的 id 值,最后再打印一下创建的这个类的 id 值(所谓的 id 值也就是内存地址),我们可以看到最后的输出结果是一致的,这也就说明,整个类的地盘是由 __new__ 函数 "开辟出来的",而到了 __init__ 内部就只能在这片地盘上 "修修补补" 了。

小结:__new__ 和 __init__ 相配合才是 python 中真正的类构造器。