先看一段代碼:
class Person:
def __new__(cls, name, age):
print('__new__ called.')
return super(Person, cls).__new__(cls)
def __init__(self, name, age):
print('__new__ called.')
self.name = name
self.age = age
def __str__(self):
return '<Person: %s(%s)>' % (self.name, self.age)
if __name__ == '__main__':
p = Person('p', 24)
print(p)
程序運行結果:
__new__ called.
__new__ called.
<Person: p(24)>
可以看出,Foo類實例化f對象時首先會運行__new__方法,再運行__init___方法。__init__不是類實例化的內置方法嗎?爲什麼又多出個__new__? 它爲什麼會在__init__方法之前運行?它是幹嘛的?
一、__new__與__init__幹嘛的
__new__:類的實例化方法,並返回該實例
__init__:實例的構造方法, 接受類的實例(self)並對其進行構造
繼承自object的新式類纔有__new__
__new__至少要有一個參數cls,代表要實例化的類,此參數在實例化時由Python解釋器自動提供
__new__必須要有返回值,返回實例化出來的實例,這點在自己實現__new__時要特別注意,可以return父類__new__出來的實例,或者直接是object的__new__出來的實例
__init__有一個參數self,就是這個__new__返回的實例,__init__在__new__的基礎上可以完成一些其它初始化的動作,__init__不需要返回值
若__new__沒有正確返回當前類cls的實例,那__init__是不會被調用的,即使是父類的實例也不行
二、__new__的作用:
1. 自定義不可變的class如:int, str, tuple, 還有就是實現自定義的metaclass。
metaclass屬於神級魔法,目前沒有掌握在此放下不表。我們看下第一個功能。
以int爲例。假如我們需要一個永遠都是正數的整數類型,通過繼承int,我們可能會這樣寫代碼。
class PositiveInteger(int):
def __init__(self, value):
super(PositiveInteger, self).__init__(self, abs(value))
i = PositiveInteger(-3)
print(i)
但是運行後發現,結果根本不是我們想要的那樣,我們任然得到-3。這是因爲對於int這種不可變的對象,我們只有重載它的__new__方法才能起到自定義的作用。
修改代碼:
class PositiveInteger(int):
def __new__(cls, value):
return super(PositiveInteger, cls).__new__(cls, abs(value))
i = PositiveInteger(-3)
print(i)
通過重載__new__方法,我們實現了需要的功能。
2. 用__new__來實現單例
如何實現單例,面試常考。媽蛋,想想自己面試第一次回答這個問題的時候就想笑,明明沒聽過單例模式傻不啦嘰的說了一大堆,面試官就聽着不說話,我以爲自己說得特對。回來百度下才直到自己蠢到家了,渣渣。
因爲類每一次實例化後產生的過程都是通過__new__來控制的,所有通過重載__new__方法,我們可以很簡單的實現單例模式。
class Singleton:
instance = None
def __new__(cls, xx, yy):
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
def __init__(self, xx, yy):
self.xx = xx
self.yy = yy
obj1 = Singleton(1, 2)
obj2 = Singleton(2, 1)
print(obj1.xx, obj2.xx)
print(obj1 is obj2)
輸出結果:2 2
True
可以看到obj1, obj2是同一個實例。
參考博客:
https://blog.csdn.net/four_infinite/article/details/52806594