python魔法方法__new__(),__init__()

Python 2的早期,確實是沒有__new__函數的,但那是很多年前的事情了,現在的Python 2和Python 3中,類實例的創建過程均遵循先調用__new__函數構造類實例,然後調用__init__函數對實例進行初始化。

先new再init
看一個簡單的例子

class Sample(object):

def new(cls):
print(“Sample.new called”)
return super().new(cls)

def init(self):
print(“Sample.init called”)

s = Sample()

上面的代碼會輸出
Sample.new called
Sample.init called
即Python解釋器會先調用__new__函數再調用__init__函數。

無new不init
class Sample(object):

def new(cls):
print(“Sample.new called”)
# return super().new(cls)

def init(self):
print(“Sample.init called”)

s = Sample()
print(s)

上面的代碼會輸出:
Sample.new called
None

自定義__new__函數的返回值
如果我們把代碼改成這樣:

class Sample(object):

def new(cls):
print(“Sample.new called”)
return 666

def init(self):
print(“Sample.init called”)

s = Sample()
print(s)
輸出:
Sample.new called
666
可以看到,__new__函數決定了我們最終創建的是什麼類型的對象。這裏Sample.__init__函數沒有被調用,因爲666是一個int類型的實例,調用的是int.__init__函數,這個函數不會輸出任何信息。當然,我們還可以返回其他類型的對象,所以__new__函數給我們帶來了很多靈活性。

另外還有一點需要注意,Python規定__init__函數只能返回None,否則會引起TypeError:
class Sample(object):

def new(cls):
print(“Sample.new called”)
return super().new(cls)

def init(self):
print(“Sample.init called”)
return 1

s = Sample()
輸出:

Sample.new called
Sample.init called
Traceback (most recent call last):
File “main.py”, line 11, in
s = Sample()
TypeError: init() should return None, not ‘int’

單例模式(Singleton)
重寫__new__函數可以帶給我們很多靈活性,例如實現單例模式,例如在遊戲中同一時刻只允許出現一個大Boss,只有Boss被打死之後,才能新召喚一個Boss:
class Boss(object):
_instance = None

def new(cls):
print(“Sample.new called”)
if cls._instance is None:
cls._instance = super().init(cls)
return cls._instance

def init(self):
print(“Sample.init called”)

boss1 = Boss()
boss2 = Boss()

print(id(boss1)) # 140620000188688
print(id(boss2)) # 140620000188688
可以看到boss1和boss2都指向同一個實例。

工廠模式(Factory)
上面我們看到,我們可以自定義__new__函數的返回值,那麼我們可以使用這個特性,實現工廠模式。同樣以遊戲爲例,我們需要一個兵工廠來給我們生產各種類型的戰士,例如地精、薩滿祭司等等:
class Soldier(object):

def init(self):
pass

def attack(self):
pass

def retreat(self):
print(“Retreat!!!”)

class Goblin(Soldier):
“”"
地精
“”"
def init(self):
pass

def attack(self):
print(“Goblins are attacking!!!”)

class Shaman(Soldier):
“”"
薩滿
“”"
def init(self):
pass

def attack(self):
print(“Shamans are attacking!!!”)

class SoldierFactory(object):
#兵工廠能夠生產的戰士類型
soldiers = {‘goblin’: Goblin, ‘shaman’: Shaman}

def new(cls, name):
if name in cls.soldiers.keys():
return cls.soldiersname
return None

goblin1 = SoldierFactory(“goblin”)
goblin2 = SoldierFactory(“goblin”)
shaman1 = SoldierFactory(“shaman”)
shaman2 = SoldierFactory(“shaman”)

goblin1.attack() # Goblins are attacking!!!
goblin2.attack() # Goblins are attacking!!!
shaman1.attack() # Shamans are attacking!!!
shaman2.attack() # Shamans are attacking!!!

goblin1.retreat() # Retreat!!!
goblin2.retreat() # Retreat!!!
shaman1.retreat() # Retreat!!!
shaman2.retreat() # Retreat!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章