1. 程式人生 > >python類:class建立 new init詳解

python類:class建立 new init詳解


在Python中,可以通過class關鍵字定義自己的類,然後通過自定義的類物件類建立例項物件。

python類的建立
建立一個Student的類,並且實現了這個類的初始化函式”__init__”,

class Student(object): #object 可省略
    count = 0
    books = []
    def __init__(self, name): #初始化

        self.name = name

大家可能對Python中的__init__方法很熟悉,認為他是例項化類時呼叫的第一個方法。但其實他並不是。例項化時呼叫的第一個方法其實是__new__方法。


類構造和初始化
”__init__”和”__new__”的聯絡和差別
下面先通過一段程式碼看看這兩個方法的呼叫順序:

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()


從程式碼的輸出可以看到,當通過類例項化一個物件的時候,”__new__”方法首先被呼叫,然後是”__init__”方法。

對於”__new__”和”__init__”可以概括為:

“__new__”方法在Python中是真正的構造方法(建立並返回例項),通過這個方法可以產生一個”cls”對應的例項物件,所以說”__new__”方法一定要有返回。對於”__init__”方法,是一個初始化的方法,”self”代表由類產生出來的例項物件,”__init__”將對這個物件進行相應的初始化操作
__new__是一個靜態方法,而__init__是一個例項方法。
__new__方法會返回一個建立的例項,而__init__什麼都不返回。
只有在__new__返回一個cls的例項時後面的__init__才能被呼叫。

當建立一個新例項時呼叫__new__,初始化一個例項時用__init__。

“__new__”是在新式類中新出現的方法,它有以下行為特性:

1、“__new__” 方法是在類例項化物件時第一個呼叫的方法,將返回例項物件
2、“__new__” 方法始終都是類的靜態方法(即第一個引數為cls),即使沒有被加上靜態方法裝飾器
3、第一個引數cls是當前正在例項化的類,如果要得到當前類的例項,應當在當前類中的 “__new__” 方法語句中呼叫當前類的父類的” __new__” 方法。

__init__的呼叫
“__new__”決定是否要使用該類的”__init__”方法,因為”__new__” 可以呼叫其他類的構造方法或者直接返回別的類建立的物件來作為本類的例項。

通常來說,新式類開始例項化時,”__new__”方法會返回cls(cls指代當前類)的例項,然後呼叫該類的”__init__”方法作為初始化方法,該方法接收這個例項(即self)作為自己的第一個引數,然後依次傳入”__new__”方法中接收的位置引數和命名引數。但是,如果”__new__”沒有返回cls(即當前類,不能是其它類)的例項,那麼當前類的”__init__”方法是不會被呼叫的。

class A(object):
    def __init__(self, *args, **kwargs):
        print "Call __init__ from %s" %self.__class__
 
    def __new__(cls, *args, **kwargs):
        obj = object.__new__(cls, *args, **kwargs)
        print "Call __new__ for %s" %obj.__class__
        return obj  
 
class B(object):
    def __init__(self, *args, **kwargs):
        print "Call __init__ from %s" %self.__class__
 
    def __new__(cls, *args, **kwargs):
        obj = object.__new__(A, *args, **kwargs)
        print "Call __new__ for %s" %obj.__class__
        return obj      
 
b = B()

print type(b)


程式碼中,在B的”__new__”方法中,通過”obj = object.__new__(A, *args, **kwargs)”建立了一個A的例項,在這種情況下,B的”__init__”函式就不會被呼叫到。


派生不可變型別
關於”__new__”方法還有一個重要的用途就是用來派生不可變型別。

例如,Python中float是不可變型別,如果想要從float中派生一個子類,就要實現”__new__”方法:

classRound2Float(float):
    def__new__(cls,num):
        num=round(num,2)
        #return super(Round2Float, cls).__new__(cls, num)
        returnfloat.__new__(Round2Float,num)
 
f=Round2Float(4.14159)
printf

程式碼中從float派生出了一個Round2Float類,該類的例項就是保留小數點後兩位的浮點數。

參考:http://blog.csdn.net/pipisorry/article/details/20803265