__new__() 是一種負責建立類執行個體的靜态方法,它無需使用 staticmethod 裝飾器修飾,且該方法會優先 __init__() 初始化方法被調用。
一般情況下,覆寫 __new__() 的實作将會使用合适的參數調用其超類的 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)
輸出結果為:
__new__(): ('abc',) {}
__init__(): <__main__.demoClass object at 0x0000026FC0DF8080> abc
__new__(): ('xyz',) {}
__init__(): <__main__.demoClass object at 0x0000026FC0DED358> xyz
0 2
1 2
__new__() 通常會傳回該類的一個執行個體,但有時也可能會傳回其他類的執行個體,如果發生了這種情況,則會跳過對 __init__() 方法的調用。而在某些情況下(比如需要修改不可變類執行個體(Python 的某些内置類型)的建立行為),利用這一點會事半功倍。比如:
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)))
運作結果為:
__init__()
那麼,什麼情況下使用 __new__() 呢?答案很簡單,在 __init__() 不夠用的時候。
例如,前面例子中對 Python 不可變的内置類型(如 int、str、float 等)進行了子類化,這是因為一旦建立了這樣不可變的對象執行個體,就無法在 __init__() 方法中對其進行修改。
有些讀者可能會認為,__new__() 對執行重要的對象初始化很有用,如果使用者忘記使用 super(),可能會漏掉這一初始化。雖然這聽上去很合理,但有一個主要的缺點,即如果使用這樣的方法,那麼即便初始化過程已經是預期的行為,程式員明确跳過初始化步驟也會變得更加困難。不僅如此,它還破壞了“__init__() 中執行所有初始化工作”的潛規則。
注意,由于 __new__() 不限于傳回同一個類的執行個體,是以很容易被濫用,不負責任地使用這種方法可能會對代碼有害,是以要謹慎使用。一般來說,對于特定問題,最好搜尋其他可用的解決方案,最好不要影響對象的建立過程,使其違背程式員的預期。比如說,前面提到的覆寫不可變類型初始化的例子,完全可以用工廠方法(一種設計模式)來替代。
Python中大量使用 __new__() 方法且合理的,就是 MetaClass 元類。有關元類的介紹,可閱讀《Python MetaClass元類》一節。