天天看點

python new方法_Python __new__()方法詳解

__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元類》一節。