2

本文旨在澄清 python 里 __new__ vs __init__cls vs self 的概念。

很多初学者会困扰,python的“魔法函数” __new__ 有啥用? 跟__init__有啥区别? 为什么有的函数第一个输入变量是self, 有的却是cls? 这有啥区别?

好,废话不多说,先看一个例子:

class A(object):
    def __new__(cls):
        print("A.__new__ called")
        return super(A, cls).__new__(cls)

    def __init__(self):
        print("A.__init__ called")

A()
print('finished')

运行结果为:

A.__new__ called
A.__init__ called
finished

为什么结果是这样呢?
因为:__new__ 负责创建一个 object;之后 __init__ 负责初始化这个 object。

有点绕是吧,再说具体点:

A()被 call 的时候,__new__ 就自动执行了, 它创建了一个object(class的具体实例)并返回这个object,然后__init__接手这个实例再接着执行。

每当__new__ 创建并返回一个实例时,__init__ 就接手这个实例然后执行,这个实例就是__init__ 的第一个输入变量,永远不变的, 默认的self。 说到这里,self怎么来的应该很清楚了吧。

在平常应用中,我们定义某个class时几乎不会去写它的__new__方法,于是当我们call这个class时,python会一直往上追溯到有__new__的父辈class, 通常我们自定义的class都是object的子类,所以执行的都是它的__new__
object__new__创建并返回的这个实例,是裸的。 然后我们的class__init__再接手这个裸的实例去进一步加工,比如加上各种 self.xxx = xxx, 或再执行一些别的code, 这个过程就是initialization。注意它和creation的区别,应该说的很清晰了吧。

那假如我们自己定义一个坏了的__new__, 它没有返回一个实例,这事会发生什么呢?比如:

class A(object):
    def __new__(cls):
        print("A.__new__ called")
        #return super(A, cls).__new__(cls)

    def __init__(self):
        print("A.__init__ called")

A()

运行一下,发现结果是:

A.__new__ called
finished

哈哈当然啦,__new__没有返回一个创建好的实例,那么__init__自然就执行不了了。 上头没有提供食材,厨子就揭不开锅做饭嘛。

这个时候有人会问了,为啥 __init__() 里面是 self, 而__new__()里面是cls呢?

首先,我们澄清一下概念:

1、self表示一个具体的实例(instance)本身。(如果用了@staticmethod,那么就可以无视这个self,因为staticmethod就可以理解成一个普通的函数)

2、cls表示这个类(class)本身。

OK, __init__() 里面的self已经说清楚了,是刚刚__new__出炉的一个创建好的实例(object / instance); 那__new__()里面是cls又是指哪个class呢?

简单说来:哪个class召唤了__new__, cls就默认是哪个class

再看一个例子 (Singleton 单例模式的实现):

class Singleton(object):

    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)

            print('\n')
            print('cls is ', cls)
            print(type(cls._instance),  cls._instance)

        else:
            print(' {}  already exists'.format(cls._instance))
        return cls._instance


class Bus(Singleton):
    def sendData(self,data):
        pass


class BusSon(Bus):
    def sendData(self,data):
        pass


if __name__ == '__main__':

    busson1 = BusSon()
    bus1 = Bus()
    print('------------------------\n')

    busson2 = BusSon()
    bus2 = Bus()

    print('------------------------\n')


    Bus.__new__(BusSon)
    Bus()
    x = Singleton.__new__(Bus)
    print(x)


kid_learning
16 声望0 粉丝