python核心編程筆記(12)- OOP

chap 13 oop(13.1-13.7)

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
    
    


    
    
    
    


        
 
       
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章