Python __new__()方法詳解

new() 是一種負責創(chuàng)建類實例的靜態(tài)方法,它無需使用 staticmethod 裝飾器修飾,且該方法會優(yōu)先 init() 初始化方法被調(diào)用。

一般情況下,覆寫 new() 的實現(xiàn)將會使用合適的參數(shù)調(diào)用其超類的 super().new(),并在返回之前修改實例。例如:

class demoClass:
    instances_created = 0
    def __new__(cls,*args,**kwargs):
        print("__new__():",cls,args,kwargs)
        instance = super().__new__(cls)
        instance.number = cls.instances_created
        cls.instances_created += 1
        return instance
    def __init__(self,attribute):
        print("__init__():",self,attribute)
        self.attribute = attribute
test1 = demoClass("abc")
test2 = demoClass("xyz")
print(test1.number,test1.instances_created)
print(test2.number,test2.instances_created)

輸出結(jié)果為:

__new__(): <class '__main__.demoClass'> ('abc',) {}
__init__(): <__main__.demoClass object at 0x0000026FC0DF8080> abc
__new__(): <class '__main__.demoClass'> ('xyz',) {}
__init__(): <__main__.demoClass object at 0x0000026FC0DED358> xyz
0 2
1 2

new() 通常會返回該類的一個實例,但有時也可能會返回其他類的實例,如果發(fā)生了這種情況,則會跳過對 init() 方法的調(diào)用。而在某些情況下(比如需要修改不可變類實例(Python的某些內(nèi)置類型)的創(chuàng)建行為),利用這一點會事半功倍。比如:

<pre class="snippet-textonly sh_sourceCode" style="margin: 0px; display: block; padding: 3px 10px; font-size: 14px; line-height: 1.6em; color: rgb(102, 102, 102); white-space: pre-wrap; overflow-wrap: break-word; background: none; border: none; border-radius: 0px;">class nonZero(int):
    def __new__(cls,value):
        return super().__new__(cls,value) if value != 0 else None
    def __init__(self,skipped_value):
        #此例中會跳過此方法
        print("__init__()")
        super().__init__()
print(type(nonZero(-12)))
print(type(nonZero(0)))</pre>

運行結(jié)果為:

__init__()
<class '__main__.nonZero'>
<class 'NoneType'>

init() 不夠用的時候,使用 new()

例如,前面例子中對 Python 不可變的內(nèi)置類型(如 int、str、float 等)進行了子類化,這是因為一旦創(chuàng)建了這樣不可變的對象實例,就無法在 init() 方法中對其進行修改。

new() 對執(zhí)行重要的對象初始化很有用,如果用戶忘記使用 super(),可能會漏掉這一初始化。雖然這聽上去很合理,但有一個主要的缺點,即如果使用這樣的方法,那么即便初始化過程已經(jīng)是預期的行為,程序員明確跳過初始化步驟也會變得更加困難。不僅如此,它還破壞了“init() 中執(zhí)行所有初始化工作”的潛規(guī)則。

注意,由于 new() 不限于返回同一個類的實例,所以很容易被濫用,不負責任地使用這種方法可能會對代碼有害,所以要謹慎使用。
一般來說,對于特定問題,最好搜索其他可用的解決方案,最好不要影響對象的創(chuàng)建過程,使其違背程序員的預期。比如說,前面提到的覆寫不可變類型初始化的例子,完全可以用工廠方法(一種設計模式來替代。

Python中大量使用 new() 方法且合理的,就是 MetaClass 元類。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容