1.類方法:(1)定義類(及方法)(2)創建實例(3)調用實例上的方法
2. 創建一個類(新式類):
class AddrBookEntry(object): # class definition
'address book entry class'
def __init__(self, nm, ph): # define constructor
self.name = nm # set name
self.phone = ph # set phone#
print 'Created instance for:', self.name
def updatePhone(self, newph): # define method
self.phone = newph
print 'Updated phone# for:', self.name
創建一個實例
>>> john = AddrBookEntry('John Doe', '408-555-1212')
Created instance for: John Doe
>>> jane = AddrBookEntry('Jane Doe', '650-555-1212')
Created instance for: Jane Doe
訪問實例屬性
>>> john
<__main__.AddrBookEntry instance at 80ee610>
>>> john.name
'John Doe'
>>> john.phone
'408-555-1212'
>>> jane.name
'Jane Doe'
>>> jane.phone
'650-555-1212'
方法調用
>>> john.updatePhone('415-555-1212')
Updated phone# for: John Doe
>>> john.phone
'415-555-1212'
創建子類
class EmplAddrBookEntry(AddrBookEntry):
'Employee Address Book Entry class'
def __init__(self, nm, ph, id, em):
AddrBookEntry.__init__(self, nm, ph)
self.empid = id
self.email = em
def updateEmail(self, newem):
self.email = newem
print 'Updated e-mail address for:', self.name
使用子類
>>> john = EmplAddrBookEntry('John Doe', '408-555-1212',42, '[email protected]')
Created instance for: John Doe
>>> john
<__main__.EmplAddrBookEntry object at 0x62030>
>>> john.name
'John Doe'
>>> john.phone
'408-555-1212'
>>> john.email
'[email protected]'
>>> john.updatePhone('415-555-1212')
Updated phone# for: John Doe
>>> john.phone
'415-555-1212'
>>> john.updateEmail('[email protected]')
Updated e-mail address for: John Doe
>>> john.email
'[email protected]'
3.面向對象編程:
類:類體由所有聲明語句,類成員定義,數據屬性和函數組成。類通常在一個模塊的頂層進行定義,以便類實例能夠在類所定義的源代碼文件中的任何地方被創建。
無虛函數或者抽象函數:如果對 OOP 很熟悉,請注意 Python 並不支持純虛函數(像 C++)或者抽象方法(如在 JAVA 中),這些都強制程序員在子類中定義方法。作爲替代方法,你可以簡單地在基類方法中引發 NotImplementedError 異常,這樣可以獲得類似的效果。
屬性鏈:有關屬性的一個有趣的地方是,當你正訪問一個屬性時,它同時也是一個對象,擁有它自己的屬性,可以訪問,這導致了一個屬性鏈
python的綁定及非綁定:Python 嚴格要求,沒有實例,方法是不能被調用的。
特殊的類屬性:
C.__name__ 類C的名字(字符串)
C.__doc__ 類C的文檔字符串
C.__bases__ 類C的所有父類構成的元組
C.__dict__ 類C的屬性
C.__module__ 類C定義所在的模塊(1.5 版本新增)
C.__class__ 實例C對應的類(僅新式類中)
4.__init__()類似於OOP中的構造函數,但是在python中它還不是真正的構造函數。當一個類被實例化的時候,__init__()就會被自動調用,而且該對象會被作爲參數傳入__init__()。如果__init__()沒有實現,則返回它的對象,如果__init__()已經被實現,那麼它將被調用,實例對象作爲第一個參數(self)被傳遞進去,像標準方法調用一樣。
5.__new__()更像一個真正的構造器,用來實例化不可變對象,比如,派生字符
串,數字,等。這種情況下,解釋器則調用類的__new__()方法,一個靜態方法,並且傳入的參數是在類實例化操作時生成的。__new__()會調用父類的__new__()來創建對象(向上代理)。它總是在__init__()之前被調用的。__new__()接受即將被創建實例的類作爲第一個參數cls,而它接收的其餘參數正是我們創建實例時傳給類的參數。所以__new__()可以表示成__new__(cls,*args,**kwargs)
eg:
class A(object):
def __new__(cls,*args,**kwargs):
print cls
print 'args is',args
ptint 'kwargs is',kwargs
>>> a = A()
cls is <class '__main__.A'>
args is ()
kwargs is {}
>>> print a #經過調用了__new__之後發現a仍然爲None
None
>>> a = A(1,2)
cls is <class '__main__.A'>
args is (1, 2) #傳給A()的參數1,2都被傳給了__new__()當中
kwargs is {}
>>> print a #經過調用了__new__之後發現a仍然爲None,可見還得需要__init__()的進一步加工
None
6.__del__():特殊的析構器,python具備(引用計數)垃圾對象回收機制,當某個實例對象的所有引用都被清除掉後這個函數纔會被執行。在定義__del__()的時候需要注意:
a.不要忘記首先調用父類的__del__()
b.調用了del x不代表調用了x.__del__()
c.如果你有一個循環引用或者其他原因,讓一個實例引用逗留,那麼該對象的__del__()可能永遠不會執行
d.__del__()未捕獲的異常會被忽略掉(因爲一些在__del__()用到的變量或許已經被刪除了)。不要在__del__()中干與實例沒任何關係的事情
e.如果你定義了__del__,並且實例是某個循環的一部分,垃圾回收器將不會終止這個循環,你需要自已顯式調用 del。
7.實例屬性
實例具有數據屬性,而對於類中定義的方法是屬於類屬性。python中的實例屬性不同於java和c++,java中的所有屬性在使用前都必須明確定義或聲明,python不僅是動態類型,而且在運行時,允許這些對象屬性的動態創建。這種特性需要謹慎使用。
在構造器中首先設置實例屬性,上文我們知道__init__()是實例創建以後第一個被調用的方法。在__init__()中設置實例屬性最好。在__init__()函數中可以爲實例屬性設置默認值,這樣就可以不用向它傳遞參數。否則就要顯示的向__init__()傳遞參數。需要注意的是,默認參數應該是不變的對象,向列表,字典這樣可變對象可以作爲靜態數據,然後在每個方法調用中來維護它們的內容。
__init__()函數應該返回None,而不應返回任何對象,否則就會報錯TypeError
通過dir()和__dict__可以看實例的屬性,通過__class__可以看實例所屬的類
8.類屬性和實例屬性
類屬性的名字空間是類,實例屬性的名字空間是實例。在訪問類屬性的時候,你可以用類來訪問類屬性,如果實例沒有同名的實例屬性的話,也可以使用實例來訪問。但是修改類屬性需要使用類名,而不是實例名。
我們只有當使用類來訪問類屬性時,才能更新類屬性的值。如果使用實例來訪問類屬性,並且同時要改變類屬性的值的行爲是不會發生的,而且只會創建一個和類屬性相同名字的實例屬性。python通過這樣的機制遮蔽了類屬性不被實例輕易修改。如果我們刪除了這個新創建的實例屬性,再次使用實例去訪問類屬性,就會發現類屬性又通過實例訪問暴露出來了。需要特別注意的,但是以上的事實在類屬性是可變對象比如字典的時候,就不一樣了。看例子:
類屬性是不變對象:
>>> class A(object):
... version = 1.2
...
>>>
>>> a = A()
>>> A.version #通過類訪問類屬性
1.2
>>> a.version #通過實例訪問類屬性
1.2
>>> a.version+=1 #通過實例訪問類屬性並且修改類屬性
>>> A.version #通過類訪問類屬性,依然不變
1.2
>>> a.version #此時已不是通過實例訪問類屬性,而是直接訪問新創建的實例屬性
2.2
>>> del a.version #刪除實例屬性
>>> a.version #類屬性重新暴露出來
1.2
類屬性是可變對象:
>>> class B(object):
... x = {123:'abc'} #類屬性是可變對象
...
>>> b = B()
>>> B.x #通過類訪問屬性
{123: 'abc'}
>>> b.x #通過實例訪問類屬性
{123: 'abc'}
>>> b.x[456]='def' #通過實例訪問類屬性並且修改類屬性
>>> B.x
{456: 'def', 123: 'abc'} #通過類訪問類屬性,竟然發現改變了
>>> b.x
{456: 'def', 123: 'abc'} #通過類訪問類屬性,改變
>>> del b.x #沒有遮蔽所以不能刪除掉
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'B' object attribute 'x' is read-only