python核心編程-第十三章-我的筆記

1.  類html

    1.1  python使用關鍵字 class 來建立類。class後跟類名,類名子後的括號中是繼承的父類。若無父類,則從 object 基類中繼承。python

class ClassName(bases):      # 繼承自"bases"
    'class documentation string'    # class的文檔字符串
    pass

class ClassName2(object):    # 無父類,則從object基類繼承
    pass

2  類屬性安全

    2.1  靜態變量/靜態數據  app

        靜態變量是與類綁定的,不依賴於實例,一般僅用來跟蹤與類相關的值。dom

>>> class C(object):
...     C.foo = 100
...
>>> print C.foo
100
>>> C.foo += 1
>>> print C.foo
101

    2.2  Methods函數

           方法是做爲類定義中的一部分的函數,僅能經過實例來調用。像調用函數那樣直接調用方法名字、或者由類對象調用都會異常ui

    2.3  類的屬性code

        要知道一個類有哪些屬性,兩種方法:①使用 dir() 內建函數 ②經過訪問類的字典屬性"__dict__",這是全部類都具有的特殊屬性。orm

        首先定義一個類:htm

# -*- coding: utf-8 -*-

class MyClass(object):
    'MyClass class definition'
    myVersion = '1.1'
    def showMyVersion(self):
        print MyClass.myVersion

        對該類調用內建函數 dir() 和字典屬性"__dict__"結果以下:

    從上面能夠看出,dir()返回對象屬性的列表,__dict__返回一個對象屬性爲key、相應的屬性對象的數據值爲value的字典。內建的vars()函數則接受類對象,返回內容和__dict__相同。

    2.4  類的特殊屬性

        對一個類C,下圖顯示了它所具備的全部特殊屬性

        

        對以前定義的MyClass,其相應的返回對象以下:

        

        __name__ 適合只須要類名字的字符串表示,而不是類對象自己的狀況,一些內建類型也有這個屬性:

        

        __doc__ 是類的文檔字符串,相似函數/模塊,是緊跟第一行下面的字符串,且不能被子類繼承。

        __bases__ 包含一個由全部父類組成的元組

        __module__ 用來定位類的位置,當類沒有使用全名時尤其重要:

>>> class C(object):
...     pass
...
>>> C
<class '__main__.C'>
>>> C.__module__
'main'
>>> from mymod import C
>>> C
<class 'mymod.C'>
>>> C.__module__
'mymod'

3.  實例

    類被實例化獲得實例,實例的類型就是被實例化的類。

    3.1  __init__() 和 __new__()

        二者之間區別與聯繫參見 http://www.cnblogs.com/ifantastic/p/3175735.html

    3.2 __del__() 解構器方法

       Python的 __del__() 是在實例的引用計數爲0即被釋放前提供特殊處理的方法,一般不被實現,由於不多會顯式的釋放實例。

       下面是一個運用了 __init__() 和 __del__() 的例子

>>> class C(P):
...     def __init__(self):
... 	    print "initialized"
...     def __del__(self):
... 	    P.__del__(self)
... 		print 'deleted'
...
>>> c1 = C()
initialized
>>> c2 = c1
>>> c3 = c1 
>>> id(c1), id(c2), id(c3)
(11938912, 11938912, 11938912)
>>> del c1 
>>> del c2 
>>> del c3
deleted

         關於 __del__() 的一些注意事項:

           

    3.3  運用 __init__() 和 __del__() 記錄實例建立次數的案例

        

4.  實例的屬性

    實例僅擁有數據屬性,它是與某個類的實例相關的值,經過句點來訪問,且獨立於其餘實例或類。

    4.1  實例化實例屬性

        設置實例屬性能夠在實例建立後,也能夠在初始化時 __init__中建立。下面是使用默認參數進行實例化的一個例子

class HotelRoomCalc(object):
    'Hotel room rate calculator'
    
    def __init__(self, rt, sales=0.085, rm=0.1):
        '''HotelRoomCalc default arguments:
        sales tax == 8.5% and room tax == 10%'''
        self.salesTax = sales
        self.roomTax = rm
        self.roomRate = rt 
        
    def calcTotal(self, days=1):
        'Calculate total; default to daily rate'
        daily = round((self.roomRate *
            (1 + self.salesTax + self.roomTax)), 2)
        return float(days) * daily

        其用法以下:

        

    4.2  查看實例屬性

        內建函數dir()也能夠查看實例屬性;實例也有一個__dict__特殊屬性,返回實例的屬性構成的一個字典,能夠用 vars() 傳入實例來獲取。

        

    4.3  實例屬性和類屬性

        4.3.1.訪問類屬性

            類屬性能夠經過類或實例來訪問,前提是沒有在實例中重定義相同名字的屬性。另外,對於不可變的屬性對象,只有類引用類的屬性時,才能更新其值;若嘗試在實例中更新,則會建立一個同名的實例屬性;對於可變對象,在實例中更新屬性會影響類中定義的屬性,因此需謹慎操做。例子以下:

        

        4.3.2.  類屬性持久性

            類屬性的修改會影響全部實例,當實例在類修改後才建立,那麼更新的值將生效

            

5.靜態方法和類方法

    靜態方法僅是類中的函數,不須要實例便可調用,經過內建函數 "staticmethod()"來實現。類方法須要類而不是實例做爲第一個參數,由解釋器傳入,類不須要特殊命名,但一般用"cls"做爲變量名,經過內建函數 "classmethod()"實現。下面是一個例子:

class TestStaticMethod:
    @staticmethod
    def foo():
        print "Calling static method foo()"
        
class TestClassMethod:
    @classmethod
    def foo(cls):
        print "Calling class method foo()"
        print "foo() is part of class:", cls.__name__

輸出:

6.  繼承

    子類能夠繼承其基類/父類的全部屬性和方法。文檔字符串除外,它不會被繼承

    6.1  __bases__

        下面的例子能夠說明 __bases__屬性與繼承的關聯:

        

        該例中,C是B的子類,同時經過B間接是A的子類,但聲明中C的父類是B,因此其__bases__屬性顯示B;而D則是聲明中就多重繼承自A、B,因此其__bases__屬性中顯示A、B

    6.2  多重繼承

        經典類的方法解釋順序是從左到右,深度優先;新式類則是廣度優先,而不是深度優先。

7.類、實例和其餘對象的內建函數

    7.1  issubclass()

       issubclass(),布爾函數,判斷一個類是不是另外一個類的子類或子孫類,語法是 issubclass(sub, sup)。當給定的類sub是sup(sup能夠是一個可能的父類組成的元組)的子類時,返回True,不然返回False。其判斷是不嚴格的,一個類是能夠視爲自身的子類的。

    7.2 isinstance()判斷一個對象是不是另外一個給定類的實例。給定類也能夠是一個可能的類型組成的元組

    7.3  *attr() 

        *attr() 系列函數能夠做用於多種對象,不侷限於類。hasattr()是布爾函數,用來檢查一個對象是否有一個特定的屬性。getattr()取得相應對象的屬性,當屬性不存在且未給出可選的默認參數時,會拋出AttributError;setattr()則要麼加入一個新屬性,要麼取代一個已存在的屬性;delattr()會從一個對象中刪除屬性

        下面是使用這一系列內建函數的例子

            

    7.4  類和類實例的內建函數包括如下各類:

    

    

8.  特殊方法定製類

    python提供了一些特殊方法用於擴充類,容許類經過重載標準操做符+、*甚至是下標或映射操做[]實現模擬標註類型。下表是全部特殊方法及描述:

    

    

    

    

    8.1  基本定製

        用RoundFloat例子來演示__str__和__repr__的用法。先看沒有定義特殊方法時的輸出:

        

        用了斷言之後,rfm輸入的數據不是浮點型時會被拋出異常;rfm實例輸入時浮點型時,獲得的卻不是想要的,即便用print 也不行。添加__str__方法後輸出以下:

        

        在定義了__str__()之後,print語句能夠打印出想要的信息,可是命令後解釋器中直接輸入對象時顯示的信息仍有問題,這能夠經過覆蓋__repr__()方法來解決。最後修改後的源代碼以下:

#!/usr/bin/env python

class RoundFloatManual(object):
    def __init__(self, val):
        assert isinstance(val, float), \
            "Value must be a float"
        self.value = round(val, 2)
    
    def __str__(self):
        return "%.2f" % self.value
    
    __repr__ = __str__

        輸出以下:

         

    8.2  數值定製

        經過實現加法和增量加法,來理解稍微複雜的特殊定製類。

        注意點:①__str__()和__repr__()定製更有意義的輸出

                      ②+重載__add__,+=重載__iadd__,obj+self用__radd__重載

                      ③計算出個別的總數之後,調用類構造器返回一個新的對象。此時不直接經過調用類名來構造類,而是用"self.__class__"屬性調用,能夠避免一些問題。

                      ④當試圖重載一個沒有定義的操做符時,會拋出TypeError。

                      ⑤在增量賦值時,區別在於__i*__方法必須返回self。

        源代碼:

#!/usr/bin/env python

class Time60(object):
    'Time60 - track hours and minutes'
    
    def __init__(self, hr, min):
        'Time60 constructor - takes hours and minutes'
        self.hr = hr 
        self.min = min
    
    def __str__(self):
        return "%s:%s" % (self.hr, self.min)
        
    __repr__ = __str__
    
    def __add__(self, other):
        return self.__class__(self.hr + other.hr,
            self.min + other.min)
            
    def __iadd__(self, other):
        self.hr += other.hr
        self.min += other.min
        return self

        輸出:

    8.3  迭代器

        8.3.1  RandSeq

            本節介紹了兩個迭代器,第一個是RandSeq,給類傳入一個初始序列,而後能夠經過next()無窮迭代,這也是惟一的亮點。

            注意點:①__iter__()方法僅返回self,這是將對象聲明爲迭代器的方式

                          ②與以前同樣,調用next()來迭代,獲得連續的值

            源代碼:

#!/usr/bin/env python

from random import choice

class RandSeq(object):
    def __init__(self, seq):
        self.data = seq 
    
    def __iter__(self):
        return self
        
    def next(self):
        return choice(self.data)

            輸出:     # 沒法結束的循環。。

        8.3.2 AnyIter

            第二個例子中建立了一個迭代器,並經過給next()傳遞一個參數,控制返回條目的數目。同時定義一個安全標識符對過程作出一些控制。

            源代碼:

#!/usr/bin/env python

class AnyIter(object):
    def __init__(self, data, safe = False):
        self.safe = safe
        self.iter = iter(data)
        
    def __iter__(self):
        return self
        
    def next(self, howmany=1):
        retval = []
        for eachitem in range(howmany):
            try:
                retval.append(self.iter.next())
            except StopIteration:
                if self.safe:
                    break
                else:
                    raise
        return retval

            輸出:

        8.4  多類型定製

            建立由數字-字符對組成的的類,數字和字符記爲n和s,數值類型使用整型,用[n::s]來表示。類NumStr具備幾個特徵:①類要對數字和字符串進行初始化,默認n=0、s=''②加法操做符把數字加起來,字符按順序鏈接③乘法操做符數字相乘、字符累積④當數字爲0且字符爲空時,類實例布爾值爲False⑤實現cmp()比較並返回適當的值

            源代碼:

#!/usr/bin/env python

class NumStr(object):
    
    def __init__(self, num=0, string=''):
        self.__num = num
        self.__string = string
        
    def __str__(self):
        return '[%d::%r]' % (self.__num, self.__string)
        
    __repr__ = __str__
    
    def __add__(self, other):
        if isinstance(other, self.__class__):
            return self.__class__(self.__num + \
                other.__num,\
                self.__string + other.__string)
        else:
            raise TypeError, \
                'Illegal argument type for built-in operation'
    
    def __mul__(self, num):
        if isinstance(num, int):
            return self.__class__(self.__num * num,\
                self.__string * num)
        else:
            raise TypeError, \
                "Illegal argument type for bulit-in operation"
    
    def __nonzero__(self):
        return self.__num or len(self.__string)
        
    def __norm_cval(self, comres):
        return cmp(comres, 0)
        
    def __cmp__(self, other):
        return self.__norm_cval(
                 cmp(self.__num, other.__num)) + \
            self.__norm_cval(
                cmp(self.__string, other.__string))

            輸出示例:

            

            

            

            注意點:①雙下劃線開始的屬性屬於內部私有變量,不要從外部直接訪問。

                          ②%r和%s的區別

                          ③__nonzzero__  覆蓋此方法定義類的布爾值

相關文章
相關標籤/搜索