Python類定義及屬性與方法說明

類基礎

類進階

 

Python的類提供了面向對象編程的所有基本功能:

  • Object類是所有類的父類(不需要明確指定);
  • 類允許繼承多個基類(使用逗號分割);
  • 派生類可覆蓋基類中任何方法;

類基礎

類支持兩種操作:

  • 實例化: inst = clsName(…)
  • 屬性引用: 使用實例對象或類(類屬性)引用對象;

類定義

類通過class定義,裏面有屬性與方法。

class ClassName:
    <statements>

    def funs(self, arg):
        # self is the instance of class
        <fun statements>

    @classmethod
    def clsFuns(cls, arg):
        # cls is the class
        <statements>

    @staticmethod
    def staticFun(arg):
        # 與普通函數類似
        <statements>

類繼承

Python支持多繼承,多個父類之間通過逗號分割。若是父類中有相同的方法名,而在子類使用時未指定,Python從左到右依次查找父類中是否包含方法(即優先使用排在前面的父類中的方法)。

在多重繼承(特別是有菱形繼承時),查找關係會更復雜;具體是通過MRO(Method Resolution Order)來解決方法調用二義性問題的;而MRO又是使用的C3算法(拓撲排序+深度優先搜索:依次取出入度爲0的節點,取出節點後即把其相關的邊去掉,然後遞歸處理)處理順序的。

子類中要調用基類中同名方法需:baseCls.funsuper().fun

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    <statement-N>

變量與可訪問性

變量(屬性)分類:

  • 類變量:直接定義在類中,爲所有類對象共享;通過類名訪問clsName.var
  • 實例變量:每個實例獨有的數據(在__init__方法中定義、初始化);通過實例對象訪問inst.var

Python中的可訪問性是通過約定來實現的:

  • 私有屬性:以兩個下劃線開始的,__var
  • 保護屬性:以一個下劃線開始的,_var;只能自身與子類可訪問;
  • 普通屬性:以字母等開始的。

類專有方法

Python中通過約定一些專有的方法來增強類的功能:

  • __init__:構造函數,在生成對象時調用(實例變量也在此函數中定義);
  • __del__:析構函數,釋放對象時使用;
  • __repr__:打印(若有__str__,則先嚐試str),轉換;
  • __setitem__:按照索引賦值;
  • __getitem__:按照索引取值;
  • __len__:獲取長度,內置函數len()使用;
  • __cmp__:比較運算;
  • __call__:函數調用(對象看作一個算子);
  • __add__:加運算;
  • __sub__:減運算;
  • __mul__:乘運算;
  • __div__:除運算;
  • __mod__:求餘運算;
  • __pow__:乘方運算;

repr與str:repr()與str()爲內置函數,對應類中的__repr____str__來處理字符串:

  • repr對Python(程序員)友好,生成的字符串應可通過eval()重構對象;
  • str爲用戶友好,方便用戶理解的輸出;
  • print時先查看__str__,若未定義,再查看__repr__

類進階

類方法

Python類中有三種方式定義方法:

  • 常規方式:定義實例方法,第一個參數表示實例(一般約定爲self);
  • @classmethod修飾方式:定義類方法,第一個參數表示類(一般約定爲cls);
  • @staticmethod修飾方式:定義靜態方法;

以下是三種函數的定義及調用方式:

class MethodTest:
    index = 0

    def __init__(self):
        self.index = -1

    def instFun(self, index):
        print('instance function:', index, self.index, MethodTest.index)
        self.index = index

    @classmethod
    def classFun(cls, index):
        print('class function:', index, cls.index)
        cls.index = index

    @staticmethod
    def staticFun(index):
        print('static function:', index, MethodTest.index)


if __name__=="__main__":
    mtest = MethodTest()
    mtest.instFun(1)  # instance function: -1 0
    mtest.classFun(2)  # class function: 0 0
    mtest.staticFun(3)  # static function: 3 2
    MethodTest.classFun(4)  # class function: 2 2
    MethodTest.instFun(mtest, 5)  # instance function: 1 4
    MethodTest.staticFun(6)  # static function: 6 4

通過實例對象可以直接調用三類方法;通過類名可以直接調用靜態方法與類方法,若要調用實例方法,還需傳遞一個實例對象。

類屬性

通過get/set屬性,可以增強對變量的控制,便於後續修改與擴展。但類中的屬性(get/set)方法不要手動去實現,應使用@propery來修飾實現:

  • 把一個get方法變成屬性,只需增加@propery修飾即可;
  • @propery本身又創建了另一個裝飾器,負責把一個setter方法變成屬性賦值:若不增加setter方法,則屬性將是隻讀的。

以下是屬性定義的示例:通過@propery定義了count的get屬性,然後就可以通過@count.setter來定義set屬性了。

class CountProp:
    def __init__(self):
        self._count=0

    @property
    def count(self):
        return self._count

    @count.setter
    def count(self, newCount):
        self._count = newCount

    def __getattr__(self, name):
        print('call __getattr__:', name)
        value = '{} value for {}'.format(self._index, name)
        self._index += 1
        setattr(self, name, value)
        return value

    def __getattribute__(self, name):
        print('call __getattribute__:', name)
        try:
            return super().__getattribute__(name)
        except AttributeError:
            # setattr(self, name, value)
            raise

cPro = CountProp()
print(cPro.count)    # 0
cPro.count = 10
print(cPro.count)    # 10    
    

類中的屬性除在類定義(或初始化時)定義外,還可以在任何時候綁定(在給不存在的屬性賦值時會自動綁定)。屬性的獲取與賦值規則爲:

  • 先調用getattribute:無論屬性是否存在(若屬性不存在,需拋出AttributeError異常),因此不能在此方法內引用屬性,否則會引起循環遞歸。因此若要訪問屬性,則調用super().XXX來避免遞歸。
  • 屬性不存在時(對象的實例字典中查詢不到屬性時),若類定義了getattr則調用此方法;
  • 當給屬性賦值或調用setattr函數時,都會觸發setattr方法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章