__new__()是新式類中才出現(xiàn)的方法,即只有從object繼承的類才有該方法。注意,,新式類是從python2.2開(kāi)始加入的,,在python2.x中同時(shí)存在新式類和舊式類(舊式類也稱經(jīng)典類,主要是為了兼容以前的代碼),但是在python3.x中已經(jīng)完全摒棄舊式類了,在python3.x中即使不顯示的寫(xiě)明從object繼承,系統(tǒng)也會(huì)默認(rèn)從object繼承,。
在舊式類中,實(shí)例的構(gòu)造只調(diào)用__init__()這一個(gè)函數(shù)(至少?gòu)耐獗韥?lái)看是如此),,因此很多場(chǎng)合稱__init__()為構(gòu)造函數(shù),,在舊式類中這完全沒(méi)問(wèn)題,但是在新式類中這么叫并不完全合適,。
在新式類中,,實(shí)例的構(gòu)造先調(diào)用__new__()函數(shù)返回一個(gè)實(shí)例,然后調(diào)用__init__()對(duì)返回的實(shí)例進(jìn)行初始化,。因此可以看出__new__()才是真正的構(gòu)造函數(shù),,__init__()只是起到了初始化的過(guò)程。
class A(object):
def __init__(self,*args,**kwargs):
print "init &&&& %s" % self.__class__
def __new__(cls,*args,**kwargs):
print "new &&&& %s" % cls
return object.__new__(cls,*args,**kwargs)
a=A()
輸出結(jié)果為:
new &&&& <class '__main__.A'>
init &&&& <class '__main__.A'>
如果把最后一行的return代碼屏蔽掉,,輸出結(jié)果為:
new &&&&<class '__main__.A'>
一般來(lái)說(shuō),,”init”和”new”函數(shù)都會(huì)有下面的形式:
def __init__(self, *args, **kwargs):
def __new__(cls, *args, **kwargs):
對(duì)于”new”和”init”可以概括為:
“new”方法在Python中是真正的構(gòu)造方法(創(chuàng)建并返回實(shí)例),通過(guò)這個(gè)方法可以產(chǎn)生一個(gè)”cls”對(duì)應(yīng)的實(shí)例對(duì)象,,所以說(shuō)”new”方法一定要有返回,。
對(duì)于”init”方法,是一個(gè)初始化的方法,,”self”代表由類產(chǎn)生出來(lái)的實(shí)例對(duì)象,,”init”將對(duì)這個(gè)對(duì)象進(jìn)行相應(yīng)的初始化操作。
重寫(xiě)_new_
如果(新式)類中沒(méi)有重寫(xiě)”new”方法,,Python默認(rèn)是調(diào)用該類的直接父類的”new”方法來(lái)構(gòu)造該類的實(shí)例,,如果該類的父類也沒(méi)有重寫(xiě)”new”,那么將一直按照同樣的規(guī)則追溯至object的”new”方法,,因?yàn)閛bject是所有新式類的基類,。
而如果新式類中重寫(xiě)了”new”方法,那么可以選擇任意一個(gè)其他的新式類(必須是新式類,,只有新式類有”new”,,因?yàn)樗行率筋惗际菑膐bject派生)的”new”方法來(lái)創(chuàng)建實(shí)例,包括這個(gè)新式類的所有前代類和后代類,只要它們不會(huì)造成遞歸死循環(huán),。
看一段例子代碼:
class Foo(object):
def __new__(cls,*args,**kwargs):
obj = object.__new__(cls,*args,**kwargs)
print "Calling __new__ for %s" % obj.__class__
return obj
class Bar(Foo):
def __new__(cls,*args,**kwargs):
obj = object.__new__(cls,*args,**kwargs)
print "Calling __new__ for %s" % obj.__class__
return obj
class Student(object):
pass
class Car(object):
def __new__(cls,*args,**kwargs):
obj = object.__new__(Bar,*args,**kwargs)
print "Calling __new__ for %s" % obj.__class__
return obj
foo = Foo()
bar = Bar()
car = Car()
運(yùn)行結(jié)果是:
Calling __new__ for <class '__main__.Foo'>
Calling __new__ for <class '__main__.Bar'>
Calling __new__ for <class '__main__.Bar'>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
_init_的調(diào)用
“new”決定是否要使用該類的”init”方法,,因?yàn)椤?strong style="box-sizing: border-box;">new” 可以調(diào)用其他類的構(gòu)造方法或者直接返回別的類創(chuàng)建的對(duì)象來(lái)作為本類的實(shí)例。
通常來(lái)說(shuō),,新式類開(kāi)始實(shí)例化時(shí),,”new”方法會(huì)返回cls(cls指代當(dāng)前類)的實(shí)例,,然后調(diào)用該類的”init”方法作為初始化方法,,該方法接收這個(gè)實(shí)例(即self)作為自己的第一個(gè)參數(shù),然后依次傳入”new”方法中接收的位置參數(shù)和命名參數(shù),。
但是,,如果”new”沒(méi)有返回cls(即當(dāng)前類)的實(shí)例,那么當(dāng)前類的”init”方法是不會(huì)被調(diào)用的,??聪旅娴睦樱?/p>
class A(object):
def __init__(self,*args,**kwargs):
print "calling __init__ from %s" % self.__class__
def __new__(cls,*args,**kwargs):
obj = object.__new__(cls,*args,**kwargs)
print "calling __new__ from %s" % obj.__class__
return obj
class B(A):
def __init__(self,*args,**kwargs):
print "calling __init__ from %s" % self.__class__
def __new__(cls,*args,**kwargs):
obj = object.__new__(A,*args,**kwargs)
print "calling __new__ from %s" % obj.__class__
return obj
b=B()
print type(b)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
代碼中,在B的”new”方法中,,通過(guò)”obj = object.new(A, *args, **kwargs)”創(chuàng)建了一個(gè)A的實(shí)例,,在這種情況下,B的”init”函數(shù)就不會(huì)被調(diào)用到,。
運(yùn)行結(jié)果是:
calling __new__ from <class
<class
派生不可變類型
關(guān)于”new”方法還有一個(gè)重要的用途就是用來(lái)派生不可變類型
例如,,python中的float類型是一個(gè)不可變類型,如果想要從float中派生出一個(gè)子類,,就可以使用”new”方法:
class Round2Float(float):
def __new__(cls,num):
num = round(num,2)
obj = float.__new__(Round2Float,num)
return obj
f=Round2Float(4.324599)
print f
這段程序從float類中派生出了一個(gè)Round2Float類,,這個(gè)類的作用就是保留小數(shù)點(diǎn)后兩位的浮點(diǎn)數(shù)。