我想了解在創建過程可以通過構造函數或通過__new__
方法創建Python類的新實例時應如何創建。特別是,我注意到在使用構造函數時,將在__new__
之後自動調用__init__
方法,而直接調用__new__
時,不會自動調用__init__
類。當通過在__new__
內嵌入對__init__
的調用來顯式調用__new__
時,我可以強制調用__init__
,但當通過構造函數創建類時,最終會調用__init__
兩次。確保__init__只在構造函數創建類實例時調用一次或__new__
例如,考慮以下玩具類,它存儲一個內部屬性,即list
對象data
:將此視爲矢量類的開始很有用。
class MyClass(object):
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls, *args, **kwargs)
obj.__init__(*args, **kwargs)
return obj
def __init__(self, data):
self.data = data
def __getitem__(self, index):
return self.__new__(type(self), self.data[index])
def __repr__(self):
return repr(self.data)
類的新實例可以使用構造函數來創建或者(實際上並不知道這是在Python正確的術語),像
x = MyClass(range(10))
或通過切片,其你可以看到在__getitem__
方法中調用__new__
。
x2 = x[0:2]
在第一種情況下,__init__
會被調用兩次(都是通過內__new__
顯式調用,然後再自動),一旦在第二個實例。很明顯,我只想在任何情況下都會調用一次__init__
。有沒有一種標準的方法來在Python中做到這一點?
注意,在我的例子,我可以擺脫__new__
方法,並重新定義__getitem__
作爲
def __getitem__(self, index):
return MyClass(self.data[index])
,但那麼這將導致一個問題,如果我以後想從MyClass
繼承,因爲如果我撥打電話像child_instance[0:2]
我會找回MyClass
的一個實例,而不是子類。
感謝@unutbu的詳細介紹。 – Abiel
這是誤導。首先'__new__'不會調用'__init__'然後返回實例。調用'__new__'來創建一個實例,然後調用'__init__'來返回'__new__'。這就是爲什麼直接調用__new__不會調用__init__。其次,'__new__'不是一個構造函數,不應該被稱爲一個。 '__init__'在官方Python文檔中被稱爲構造函數。 – Ben
@Ben,你有沒有從Python文檔的參考?看起來這將清理很多關於'__init__'是否是構造函數的爭論... https://stackoverflow.com/questions/6578487/init-as-a-constructor – pylang