Python和c++一樣,可以定義類,可以繼承,類中又包含了類變數、例項變數(私有變數和公有變數)、方法(包括靜態方法staticmethod、類方法classmethod和例項方法instancemethod)。這裡只著重介紹類的成員。
透過語言描述會比較費事,下面透過例子來說明
# coding: utf-8 class MyClass: '''I simple example class''' val1 = 'Value 1' #類變數 val4 = 1 def __init__(self): self.val2 = 'Value 2' #公有例項變數 self.__val3 = 'Value 3' #私有例項變數 def __func(): print 'val1 : ', MyClass.val1 print 'static method cannot access val2' print 'static method cannot access __val3' print 'val4 : ', MyClass.val4 MyClass.val4 = ((MyClass.val4 + 1)) smd = staticmethod(__func) def __func2(cls): print 'val1 : ', cls.val1 print 'class method cannot access val2' print 'class method cannot access __val3' print 'val4 : ', cls.val4 cls.val4 = ((cls.val4 + 1)) cmd = classmethod(__func2) def func3(self): print 'val1 : ', self.val1 print 'val2 : ', self.val2 print 'instance method cannot access __val3' print 'val4 : ', self.val4 self.val4 = ((self.val4 + 1))
這個類中已經基本包含了上面提到的類中的各種成員,然後透過呼叫看下這些成員有什麼不同
print '--------------------MyClass.smd()-------------------' MyClass.smd() #類呼叫靜態方法 print '--------------------MyClass.cmd()-------------------' MyClass.cmd() #類呼叫類方法 #MyClass.func3() #類無法直接呼叫例項方法 x = MyClass() print '--------------------x.smd()-------------------' x.smd() #例項呼叫靜態方法 print '--------------------x.cmd()-------------------' x.cmd() #例項呼叫類方法 print '--------------------x.func3()-------------------' x.func3() #例項呼叫例項方法 #結果 --------------------MyClass.smd()------------------- val1 : Value 1 static method cannot access val2 static method cannot access __val3 val4 : 1 --------------------MyClass.cmd()------------------- val1 : Value 1 class method cannot access val2 class method cannot access __val3 val4 : 2 --------------------x.smd()------------------- val1 : Value 1 static method cannot access val2 static method cannot access __val3 val4 : 3 --------------------x.cmd()------------------- val1 : Value 1 class method cannot access val2 class method cannot access __val3 val4 : 4 --------------------x.func3()------------------- val1 : Value 1 val2 : Value 2 instance method cannot access __val3 val4 : 5
結合上面的輸出結果來解釋下不同變數和方法的功能。
靜態方法,可以認為是一種全域性方法,因為它不需要類例項化就能訪問,和模組內的方法沒什麼區別,可以透過類和例項進行呼叫,它不能訪問例項變數。當然,但能夠透過類名訪問類變數,如MyClass.val1。
類方法,類似是個全域性方法,它也能如靜態方法那樣被類呼叫,也能被例項呼叫,不同的是它透過例項來訪問類變數,有類變數cls傳入,並且有子類繼承時,呼叫該類方法時,傳入的類變數cls是子類,而非父類,如x.val1。
例項方法,例項方法只能透過例項訪問,它能夠訪問例項變數(公有)和類變數。
私有方法,無法被類和例項呼叫。
類變數,能夠被類、類方法、例項和例項方法等訪問。且在類和例項中進行傳遞(不停累加),如val4。
例項變數(公有),能被例項和例項方法訪問,但不能被類和類方法訪問。
例項變數(私有),不能被任何例項訪問,但我們可以透過裝飾器對其增加get/set方法來進行操作,具體在下面介紹。
私有屬性,透過在變數和方法前增加__(兩個下劃線)來定義。
裝飾器
簡單的說,裝飾器就是對函式的一種裝飾,可以在不修改被裝飾函式定義和呼叫的情況下,增加對被呼叫函式的操作或指定其屬性。
語法糖
透過裝飾器簡化方法裝飾的程式碼
# coding: utf-8 def deco(func): def _deco(): print("before myfunc() called.") func() print(" after myfunc() called.") return _deco @deco def myfunc(): print(" myfunc() called.") return 'ok' myfunc() myfunc() #輸出 before myfunc() called. myfunc() called. after myfunc() called. before myfunc() called. myfunc() called. after myfunc() called.
多層裝飾器
@A @B @C def func(): ...
可以看成是A(B(C(func))),依次執行A、B、C和func。
內建裝飾器(將上面的MyClass類重新用裝飾器定義一次,並增加對私有變數的操作方法)
# coding: utf-8 class MyClass: '''I simple example class''' val1 = 'Value 1' val4 = 1 def __init__(self): self.val2 = 'Value 2' self.__val3 = 'Value 3' def func3(self): #定義例項方法 print 'val1 : ', self.val1 print 'val2 : ', self.val2 print 'instance method cannot access __val3' print 'val4 : ', self.val4 self.val4 = ((self.val4 + 1)) @classmethod #定義類方法 def func2(cls): print 'val1 : ', cls.val1 print 'class method cannot access val2' print 'class method cannot access __val3' print 'val4 : ', cls.val4 cls.val4 = ((cls.val4 + 1)) @staticmethod #定義靜態方法 def func(): print 'val1 : ', MyClass.val1 print 'static cannot access val2' print 'static method cannot access __val3' print 'val4 : ', MyClass.val4 MyClass.val4 = ((MyClass.val4 + 1)) @property #私有例項變數get屬性 def val3(self): return self.__val3 @val3.setter #私有例項變數set屬性 def val3(self, value): self.__val3 = value @val3.deleter #私有例項變數del屬性 def val3(self): del self.__val3
@classmethod和@staticmethod分別代替了之前的類方法和靜態方法的宣告方式,除了簡潔外沒有其它特殊的意義。
在2中定義的類中,有一個私有例項變數,它不能被類和例項所訪問,我們透過增加@property和@setter來使例項能夠對私有變數進行訪問和賦值,並可以透過@deleter來將該變數刪除。注意,類也能透過@property進行私有變數的訪問,但無法透過@setter來給私有變數賦值,且@deleter不支援類訪問。
呼叫如下:
print '-------------------MyClass.func()------------------' MyClass.func() x = MyClass() print '-------------------x.func()------------------' x.func() print '-------------------x.func2()------------------' x.func2() print '-------------------x.func3()------------------' x.func3() print '' print 'MyClass().val3 : ',MyClass().val3 #類呼叫property MyClass().val3 = 'New Value' #類呼叫setter print 'after "MyClass().val3 = New Value" val3 :', MyClass().val3 print'' print 'val3 : ',x.val3 #例項呼叫property x.val3 = 'New Value' #例項呼叫setter print 'after "x.val3 = New Value" val3 :', x.val3 del x.val3 #例項呼叫deleter print 'after "del x.val3" val3 : ', x.val3 #結果 -------------------MyClass.func()------------------ val1 : Value 1 static cannot access val2 static method cannot access __val3 val4 : 1 -------------------x.func()------------------ val1 : Value 1 static cannot access val2 static method cannot access __val3 val4 : 2 -------------------x.func2()------------------ val1 : Value 1 class method cannot access val2 class method cannot access __val3 val4 : 3 -------------------x.func3()------------------ val1 : Value 1 val2 : Value 2 instance method cannot access __val3 val4 : 4 MyClass().val3 : Value 3 #類呼叫property after "MyClass().val3 = New Value" val3 : Value 3 #類呼叫setter沒有生效 val3 : Value 3 #例項呼叫property after "x.val3 = New Value" val3 : New Value #例項呼叫setter after "del x.val3" val3 : Value 3 #例項呼叫deleter