Python 物件實例化涉及 __new__ 與 __init__ 兩個關鍵方法。__new__ 負責建立實例(配置記憶體),__init__ 負責初始化實例。本文深入剖析兩者調用順序、參數差異、返回值約束、新式類與經典類差異,並示範自訂實例建立邏輯。
| 特性 | 經典類 (Python 2) | 新式類 (Python 2 繼承 object / Python 3 預設) |
|---|---|---|
| 定義 | class A: | class A(object): |
| 繼承搜尋 | 深度優先 (DLR) | 廣度優先 (MRO/C3) |
__slots__ | 不支援 | 支援 |
__getattribute__ | 無 | 有 |
__new__ | 無 | 內建 |
__class__ 屬性 | 間接取得 | 直接取得 |
ClassName(...) 觸發 __new____new__(cls, *args, **kwargs) 接收類別物件 cls (type 類型)__new__ 必須回傳實例 (通常呼叫 super().__new__(cls) 或 object.__new__(cls))self 傳給 __init____init__(self, *args, **kwargs) 初始化實例屬性
class Display(object):
def __init__(self, *args, **kwargs):
print("init")
def __new__(cls, *args, **kwargs):
print("new")
print(type(cls)) #
return object.__new__(cls, *args, **kwargs)
a = Display()
# 輸出:
# new
#
# init
class Another(object):
def __new__(cls, *args, **kwargs):
print("newano")
return object.__new__(cls, *args, **kwargs)
class Display(object):
def __init__(self, *args, **kwargs):
print("init")
def __new__(cls, *args, **kwargs):
print("newdis")
return Another.__new__(cls, *args, **kwargs)
a = Display()
# 輸出:
# newdis
# newano
# init
結論:__new__ 決定實例的「出生」,__init__ 決定實例的「成長」;兩者可解耦。
__new__ 控制實例唯一性__new__ 建立後凍結狀態__new__ 回傳現有實例__new__ 依參數回傳不同子類實例__new__ 在類別建立時介入
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls)
return cls._instance
a = Singleton()
b = Singleton()
print a is b # True
| 維度 | __new__ | __init__ |
|---|---|---|
| 調用時機 | 實例建立前 | 實例建立後 |
| 第一參數 | cls (類別物件) | self (實例物件) |
| 必須回傳 | 實例 (否則 __init__ 不被調用) | 無 (忽略返回值) |
| 可被繼承 | 是 | 是 |
| 常見用途 | 控制建立、單例、不可變、子類分派 | 屬性初始化、資源獲取 |