python面向?qū)ο笾衉_new__和__init__區(qū)別
在 Python 的面向?qū)ο缶幊讨校琠_new__ 和 __init__ ,它們的職責(zé)、執(zhí)行順序和返回值完全不同。
__new__ 負(fù)責(zé)“出生”(創(chuàng)建實(shí)例),__init__ 負(fù)責(zé)“成長(zhǎng)”(初始化屬性)。
1. 核心區(qū)別對(duì)比表
| 特性 | __new__ | __init__ |
|---|---|---|
| 本質(zhì) | 靜態(tài)方法(不需要 self ) | 實(shí)例方法 |
| 執(zhí)行時(shí)機(jī) | 最先執(zhí)行,在實(shí)例創(chuàng)建之前 | 隨后執(zhí)行,在實(shí)例創(chuàng)建之后 |
| 主要職責(zé) | 創(chuàng)建并返回一個(gè)新的實(shí)例對(duì)象 | 初始化已經(jīng)創(chuàng)建的實(shí)例對(duì)象(賦值屬性) |
| 第一個(gè)參數(shù) | cls (類本身) | self (剛剛創(chuàng)建好的實(shí)例) |
| 返回值 | 必須返回一個(gè)實(shí)例對(duì)象 (通常由 super().__new__(cls) 返回) | 不需要返回值 (默認(rèn)返回 None,若返回其他值會(huì)報(bào)錯(cuò)) |
| 使用場(chǎng)景 | 繼承不可變類型、單例模式、控制實(shí)例創(chuàng)建過程 | 絕大多數(shù)常規(guī)的屬性初始化 |
2. 執(zhí)行流程詳解
當(dāng)你調(diào)用 MyClass() 時(shí),Python 內(nèi)部實(shí)際上做了以下步驟:
- 調(diào)用 __new__ 方法:
- 傳入類 cls。
- 內(nèi)存中分配空間,創(chuàng)建一個(gè)空的對(duì)象。
- 返回這個(gè)新對(duì)象。
- 如果 __new__ 返回的是該類的實(shí)例,Python 會(huì)自動(dòng)調(diào)用 __init__ 方法:
- 將 __new__ 返回的對(duì)象作為 self 傳入。
- 執(zhí)行初始化代碼(如 self.name = ...)。
- __init__ 執(zhí)行完畢,對(duì)象完全準(zhǔn)備好。
3. 代碼示例
場(chǎng)景 A:常規(guī)用法(只看init)
99% 的情況下,你只需要寫 __init__,因?yàn)?__new__ 默認(rèn)由 object 類處理好了。
class Person:
def __init__(self, name):
print(f"2. __init__ 被調(diào)用,正在初始化: {name}")
self.name = name
p = Person("Alice")
# 輸出:
# 2. __init__ 被調(diào)用,正在初始化: Alice
場(chǎng)景 B:同時(shí)展示兩者(看執(zhí)行順序)
class Demo:
def __new__(cls, *args, **kwargs):
print("1. __new__ 被調(diào)用:負(fù)責(zé)創(chuàng)建實(shí)例")
# 必須調(diào)用父類的 __new__ 來真正創(chuàng)建對(duì)象,否則 __init__ 不會(huì)執(zhí)行
instance = super().__new__(cls)
return instance
def __init__(self, value):
print("2. __init__ 被調(diào)用:負(fù)責(zé)初始化屬性")
self.value = value
obj = Demo(100)
print(f"最終對(duì)象值: {obj.value}")
輸出結(jié)果:
1. __new__ 被調(diào)用:負(fù)責(zé)創(chuàng)建實(shí)例
2. __init__ 被調(diào)用:負(fù)責(zé)初始化屬性
最終對(duì)象值: 100
4. 什么時(shí)候必須使用__new__?
既然 __init__ 這么好用,為什么還需要 __new__?主要在以下三種高級(jí)場(chǎng)景:
① 繼承不可變類型(如int,str,tuple)
不可變類型一旦創(chuàng)建就不能修改。__init__ 是在對(duì)象創(chuàng)建后才運(yùn)行的,此時(shí)對(duì)象已經(jīng)定型,無法修改其值。必須在創(chuàng)建時(shí)(__new__)就確定值。
class MyInt(int):
# 想要強(qiáng)制讓生成的整數(shù)都是偶數(shù)
def __new__(cls, value):
# 在創(chuàng)建之前就修改值
if value % 2 != 0:
value += 1
return super().__new__(cls, value)
# __init__ 在這里無法修改整數(shù)的值,因?yàn)?int 是不可變的
num = MyInt(5)
print(num) # 輸出 6 (自動(dòng)變成了偶數(shù))
② 實(shí)現(xiàn)單例模式 (Singleton)
確保一個(gè)類只有一個(gè)實(shí)例??梢栽?__new__ 中判斷實(shí)例是否已存在,如果存在則直接返回舊的,不再創(chuàng)建新的。
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
print("創(chuàng)建新實(shí)例")
cls._instance = super().__new__(cls)
else:
print("返回已有實(shí)例")
return cls._instance
def __init__(self, name):
# 注意:即使返回舊實(shí)例,__init__ 仍會(huì)被調(diào)用,通常需要小心處理
self.name = name
s1 = Singleton("A")
s2 = Singleton("B")
print(s1 is s2) # True (是同一個(gè)對(duì)象)
print(s2.name) # "B" (注意:__init__ 再次運(yùn)行覆蓋了名字)
③ 控制實(shí)例的創(chuàng)建過程
比如根據(jù)參數(shù)決定返回哪個(gè)類的實(shí)例(工廠模式的一種變體),或者限制只能創(chuàng)建特定數(shù)量的實(shí)例。
class Shape:
def __new__(cls, shape_type, *args, **kwargs):
if shape_type == "circle":
return super().__new__(Circle)
elif shape_type == "square":
return super().__new__(Square)
return super().__new__(cls)
class Circle(Shape):
pass
class Square(Shape):
pass
c = Shape("circle")
print(type(c)) # <class '__main__.Circle'>
總結(jié)
- 日常開發(fā):只用 __init__。
- 需要修改不可變對(duì)象、控制實(shí)例生成(單例)、或動(dòng)態(tài)返回不同子類實(shí)例時(shí):使用 __new__。
- 記?。篲_new__ 是造物主(返回實(shí)例),__init__ 是裝修工(修飾實(shí)例)。如果沒有造物主造出房子,裝修工是無活可干的。
到此這篇關(guān)于python面向?qū)ο笾衉_new__和__init__區(qū)別的文章就介紹到這了,更多相關(guān)python __new__和__init__區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- python中__new__函數(shù)的具體使用
- Python中的?__init__、__new__?和?__call__示例詳解
- Python中的魔術(shù)方法__new__詳解
- Python中__new__()方法適應(yīng)及注意事項(xiàng)詳解
- python中__new__和__init__的實(shí)現(xiàn)
- 詳解Python中__new__和__init__的區(qū)別與聯(lián)系
- python __init__與 __new__的區(qū)別
- 詳解Python中__new__方法的作用
- Python 中類的構(gòu)造方法 __New__的妙用
- Python 中 __new__的實(shí)現(xiàn)示例
相關(guān)文章
Python用棧實(shí)現(xiàn)隊(duì)列的基本操作
隊(duì)列(Queue)和棧(Stack)是常見的數(shù)據(jù)結(jié)構(gòu),它們?cè)谟?jì)算機(jī)科學(xué)中有著廣泛的應(yīng)用,在Python中,可以使用列表(List)來實(shí)現(xiàn)棧,但要用棧來實(shí)現(xiàn)隊(duì)列需要一些巧妙的操作,本文就給大家詳細(xì)介紹一下Python中如何用棧實(shí)現(xiàn)隊(duì)列,需要的朋友可以參考下2023-11-11
python的pip配置的國(guó)內(nèi)鏡像的實(shí)現(xiàn)
本文主要介紹了python的pip配置的國(guó)內(nèi)鏡像的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-05-05
Python類中使用cursor.execute()時(shí)語法錯(cuò)誤的解決方法
在 Python 類中使用 cursor.execute() 時(shí),出現(xiàn)語法錯(cuò)誤(如 SyntaxError 或 SQL 語法相關(guān)錯(cuò)誤)通常是因?yàn)?nbsp;SQL 語句格式不正確、占位符使用不當(dāng),或參數(shù)傳遞方式不符合預(yù)期,以下是解決此類問題的常見方法和建議,需要的朋友可以參考下2024-09-09
tensorflow指定CPU與GPU運(yùn)算的方法實(shí)現(xiàn)
這篇文章主要介紹了tensorflow指定CPU與GPU運(yùn)算的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
Python中的錯(cuò)誤和異常處理簡(jiǎn)單操作示例【try-except用法】
這篇文章主要介紹了Python中的錯(cuò)誤和異常處理簡(jiǎn)單操作,結(jié)合實(shí)例形式分析了Python中try except在錯(cuò)誤與異常處理中的用法,需要的朋友可以參考下2017-07-07
關(guān)于PySnooper 永遠(yuǎn)不要使用print進(jìn)行調(diào)試的問題
這篇文章主要介紹了關(guān)于PySnooper 永遠(yuǎn)不要使用print進(jìn)行調(diào)試的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03

