本文旨在澄清 python 裏 __new__
vs __init__
和 cls
vs self
的概念。 python
不少初學者會困擾,python的「魔法函數」 __new__
有啥用? 跟__init__
有啥區別? 爲何有的函數第一個輸入變量是self
, 有的倒是cls
? 這有啥區別?函數
好,廢話很少說,先看一個例子:code
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')
運行結果爲:orm
A.__new__ called A.__init__ called finished
爲何結果是這樣呢?
由於:__new__
負責建立一個 object;以後 __init__
負責初始化這個 object。it
有點繞是吧,再說具體點:io
當A()
被 call 的時候,__new__
就自動執行了, 它建立了一個object(class的具體實例)並返回這個object,而後__init__
接手這個實例再接着執行。 form
每當__new__
建立並返回一個實例時,__init__
就接手這個實例而後執行,這個實例就是__init__
的第一個輸入變量,永遠不變的, 默認的self
。 說到這裏,self
怎麼來的應該很清楚了吧。class
在日常應用中,咱們定義某個class
時幾乎不會去寫它的__new__
方法,因而當咱們call這個class
時,python會一直往上追溯到有__new__
的父輩class, 一般咱們自定義的class都是object
的子類,因此執行的都是它的__new__
。object
的__new__
建立並返回的這個實例,是裸的。 而後咱們的class
的__init__
再接手這個裸的實例去進一步加工,好比加上各類 self.xxx = xxx
, 或再執行一些別的code, 這個過程就是initialization。注意它和creation的區別,應該說的很清晰了吧。變量
那假如咱們本身定義一個壞了的__new__
, 它沒有返回一個實例,這事會發生什麼呢?好比:object
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
呢?
首先,咱們澄清一下概念:
一、self
表示一個具體的實例(instance)
自己。(若是用了@staticmethod
,那麼就能夠無視這個self,由於staticmethod就能夠理解成一個普通的函數)
二、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)