python中的__new__、__init__和__del__
__new__、__init__、__del__三個方法用於例項的建立和銷燬,在使用python的類中,我們最常用的是__init__方法,通常稱為構造方法,__new__方法幾乎不會使用,這篇文章是基於Python3.6為基礎來做實驗,主要談一談python的__new__和__init__,__init__ 通常稱為構造方法,但其實它是個“初始化方法”,真正的構造方法是 __new__, __init__既然是初始化方法,那麼肯定是對物件的初始化,也就是存在一個被初始化的物件來看第一個例子:
class inch(): def __init__(self): print("__init__") def __new__(cls): print("__new__ ") print("__new__ ")__new__None
因為我們沒有從__new__返回任何結果,__init__這裡不會呼叫。如果init被呼叫,我們就會看到我們在init中的列印語句。
再看第二個例子:
class inch(): def __new__(cls): print("__new__ ") print(super(inch, cls).__new__(cls)) return super(inch, cls).__new__(cls) def __init__(self): print("__init__")print(inch())__new__<__main__.inch object at 0x002BF170>__init__<__main__.inch object at 0x002BF170>
用於構建例項的是特殊方法 __new__:是個類方法(不需要使用@classmethod),呼叫 __init__ 方法時要傳入例項,__new__必須返回一個例項。返回的例項會作為第一個引數(即 self)傳給 __init__ 方法。注意:__init__不允許返回任何值
再看第三個列子:
class inch(float): def __new__(cls, args=0.0): cls.new = float.__new__(cls,args*0.0254) return cls.new def __init__(self,a): print("__init__") print(a)object1=inch(3)print(object1.new)__init__30.07619999999999999
__init__方法中除了self之外定義的引數,都必須與__new__方法中除cls引數之外的引數保持一致
無論我們給超類的__new__傳遞的是哪個類,它都會建立該類的一個例項,如何我們想要建立一個inch的例項,所以,inch類必須作為第一個引數傳遞給float.__new__。在類inch的內部,cls指的是inch類,因此,我們需要將cls作為第一個引數傳遞給物件。
第四個例子:
class B(float): passclass inch(float): def __new__(cls, args=0.0): B.new = float.__new__(B,args*0.0254) return B.new def __init__(self,a): print("__init__") print(a)object1=inch(3)print(type(object))print(object1.new)<class '__main__.B'>0.0761999999999999
最後:__new__是用來建立一個例項的,從 object 類繼承的已經很完善。所以我們基本上不需要自己編寫 __new__ 方法第四個例子,一個__new__的應用,著名的單例模式(:python 中 None
物件就是單例):
class Singleton: _instance = None def __new__(cls, *args, **kwargs): if not isinstance(cls._instance, cls): cls._instance = object.__new__(cls, *args, **kwargs) return cls._instancea=Singleton()b=Singleton()print(a is b)True
__del__:在需要銷燬例項的時候,python直譯器會呼叫__del__方法。Cpython中垃圾回收的主要演算法是引用計數,每個物件會統計有多少引用指向自己。當引用計數歸零時,物件立即就被銷燬