定義
Python 的 Class 比較特別,和我們習慣的靜態語言類型定義有很大區別。
1. 使用一個名爲 __init__ 的方法來完成初始化。
2. 使用一個名爲 __del__ 的方法來完成類似析購操作。
3. 所有的實例方法都擁有一個 self 參數來傳遞當前實例,類似於 this。
4. 可以使用 __class__ 來訪問類型成員
def __init__(self):
print "initialize."
def Foo(self):
print id(self)
>>>>>> a = MyClass()
initialize.
>>>>>> a.Foo()
14412576
>>>>>> id(a)
14412576
Class 有一些特殊的屬性,便於我們獲得一些額外的信息。
"""This is MyClass's Docoment"""
def __init__(self):
self.i = 1234
>>>>>> MyClass.__doc__ # 類型幫助信息
"This is MyClass's Docoment""This is MyClass's Docoment"
>>>>>> MyClass.__name__ # 類型名稱
'MyClass'
>>>>>> MyClass.__module__ # 類型所在模塊
'__main__'
>>>>>> MyClass.__bases__ # 類型所繼承的基類(Python 支持多繼承)
(<type 'object'>,)
>>>>>> MyClass.__dict__ # 類型字典,存儲所有類型成員信息
<dictproxy object at 0x00DC1AD0>
>>>>>> #以下是實例擁有的屬性
>>>>>> MyClass().__class__ # 實例的類型
<class '__main__.MyClass'>
>>>>>> MyClass().__module__ # 實例類型所在模塊
'__main__'
>>>>>> MyClass().__dict__ # 對象字典,存儲所有實例成員信息
{'i': 1234}
>>>>>>
繼承
Python 支持多繼承,但有幾點需要注意:
1. 基類 __init__ / __del__ 需顯示調用。
2. 繼承方法的調用和基類聲明順序有關。
def __init__(self):
print "Base1"
def test(self):
print "Base1 test"
>>>>>> class Base2:
def __init__(self):
print "Base2"
def test(self):
print "Base2 test"
>>>>>> class MyClass(Base2,Base1):
def __init__(self):
Base1.__init__(self)
Base2.__init__(self)
print "MyClass"
>>>>>> a = MyClass()
Base1
Base2
MyClass
>>>>>> a.test()
Base2 test
>>>>>> # 下面把 Base1 放在前面
>>>>>> class MyClass(Base1,Base2):
def __init__(self):
Base1.__init__(self)
Base2.__init__(self)
print "MyClass"
>>>>>> a = MyClass()
Base1
Base2
MyClass
>>>>>> a.test()
Base1 test
>>>>>>
成員
Python Class 同樣包含類型和實例兩種成員。i = 123 # 類成員
def __init__(self):
self.i = 100 # 實例成員
>>>>>> print Class1.i
123
>>>>>> print Class1().i
100
>>>>>>
有幾個很 "特殊" 的 "規則" 需要注意。
(1) 我們可以通過實例引用訪問類型成員。因此下面的例子中 self.i 實際指向 Class1.i,直到我們爲實例新增了一個成員 i。
>>>>>> class Class1:
i = 123
def __init__(self):
print self.i
print hex(id(self.i))
>>>>>> hex(id(Class1.i)) # 顯示 Class1.i 的地址
'0xab5860'
>>>>>> a = Class1() # 創建 Class1 實例,我們會發現 self.i 實際指向
Class1.i
123
0xab5860
>>>>>> Class1.__dict__ # 顯示 Class1 成員
{'i': 123, '__module__': '__main__', '__doc__':
None, '__init__': <function __init__ at 0x012911B0>}
>>>>>> a.__dict__ # 顯示實例成員
{}
>>>>>> a.i = 100 # 爲實例新增加一個成員i
>>>>>> hex(id(a.i)) # 顯示新成員i的地址
'0xab5974'
>>>>>> a.__dict__ # 顯示實例成員
{'i': 100}
>>>>>>
(2) 調用類型內部方法,需要省略 self 參數。
def __init__(self):
self.__test("Hello Python")
def __test(self, s):
print s
>>>>>> Class1()
Hello Python
<__main__.Class1 instance at 0x00DC3800>
>>>>>>
我們可以在成員名稱前添加 "__" 使其成爲私有成員。
__i = 123
def __init__(self):
self.__x = 0
def __test(self):
print id(self)
>>>>>> Class1.i
Traceback (most recent call last):
File "<pyshell#203>", line 1, in <module>
Class1.i
AttributeError: class Class1 has no attribute 'i'
>>>>>> Class1().__x
Traceback (most recent call last):
File "<pyshell#204>", line 1, in <module>
Class1().__x
AttributeError: Class1 instance has no attribute '__x'
>>>>>> Class1().__test()
Traceback (most recent call last):
File "<pyshell#205>", line 1, in <module>
Class1().__test()
AttributeError: Class1 instance has no attribute '__test'
>>>>>>
事實上這只是一種規則,並不是編譯器上的限制。我們依然可以用特殊的語法來訪問私有成員。
123
>>>>>> a = Class1()
>>>>>> a._Class1__x
0
>>>>>> a._Class1__test()
14432256
>>>>>>
除了靜態(類型)字段,我們還可以定義靜態方法。
@staticmethod
def test():
print "In Static method"
>>>>>> Class1.test()
In Static method
>>>>>>
從設計的角度,或許更希望用屬性(property)來代替字段(field)。
def __init__(self):
self.__i = 1234
def getI(self): return self.__i
def setI(self, value): self.__i = value
def delI(self): del self.__i
I = property(getI, setI, delI, "Property I")
>>>>>> a = Class1()
>>>>>> a.I
1234
>>>>>> a.I = 1000
>>>>>> a.I
1000
如果只是 readonly property,還可以用另外一種方式。
def __init__(self):
self.__i = 1234
@property
def I(self):
return self.__i
>>>>>> a = Class1()
>>>>>> a.I
1234
用 __getitem__ 和 __setitem__ 可以實現 C# 索引器的功能。
def __init__(self):
self.__x = ["a", "b", "c"]
def __getitem__(self, key):
return self.__x[key]
def __setitem__(self, key, value):
self.__x[key] = value
>>>>>> a = Class1()
>>>>>> a[1]
'b'
>>>>>> a[1] = "xxx"
>>>>>> a[1]
'xxx'
>>>>>>