Python3學習筆記(7)—— 面向對象編程

1    面向對象編程

1.1   類

1.1.1   定義

命名:類名通常由大寫字母打頭,數據屬性使用名詞,方法使用謂詞(動詞加對象)。推薦使用下劃線方式。

類是一個type的實例。如果定義一個類C,則type(C) 是type

可以定義一個空的類,僅用作名稱空間容器,然後動態綁定實例屬性。

Python 不支持純虛函數,因此必須在子類中定義方法。

類的定義:

class Sample(baseClass):

'class documentation string'         #類文檔字符串

    def __init__(self, val1, val2):    #子類最好定義它自己的構造器,否則基類的構造器會被調用

          baseClass.__init__(self,val1)#需顯式傳遞self 實例對象給基類構造器,因爲這不是在實例中調用方法。

          self.Val2=val2

1.1.2   類屬性

①類屬性僅與其被定義的類相綁定。類屬性可通過類或實例來訪問。非靜態函數的類方法,只能通過實例訪問。

class C(object):

foo = 100

def show():pass

def show1(self):pass 

    @staticmethod

    def show2():pass

    @classmethod

    def show3(cls):pass

 

類的數據屬性,靜態數據,相當於加上了static。調用時C.foo

參數爲空。類的方法屬性,靜態方法,調用時C.show(),不能用實例調用。

self變量表示類實例,用於與實例綁定,通過實例來調用。

 

靜態方法修飾符,下邊的函數可以通過類名、實例直接訪問。

 

類方法修飾符,下邊函數可通過類名、實例直接訪問。但有cls默認參數。

②可以使用一個靜態成員(如起名爲count)來記錄實例的個數。

③訪問一個類屬性的時候,Python 解釋器將會搜索字典以得到需要的屬性。如果在__dict__中沒有找到,將會在基類的字典中進行搜索,採用“深度優先搜索”順序。

特殊的類屬性

C.__name__

類C的名字(字符串)

C.__doc__

類C的文檔字符串

C.__bases__

類C的所有父類構成的元組

C.__dict__

或內建函數vars(C)

類C的“屬性:值”字典,字符串描述。不包含父類屬性,

包括__dict__,__doc__,__module__,__weakref__以及自定義的屬性;若未定義__init__(),則不會顯示。不要修改__dict__的值。

而實例的__dict__僅存儲與該實例相關的實例屬性,未綁定屬性則是空字典。

C.__module__

對類C定義所在的模塊名(字符串)

C.__class__

對實例C對應的類(若對一個類求__class__,則得到“type”)的引用

1.2   實例化

1.2.1   __init__()初始化方法

在實例化時被自動調用,參數self把實例對象自動傳入__init__()。

__init__()是解釋器創建一個實例後,調用的第一個方法,因此嚴格意義上不是構造器。不應有非None返回值。

1.2.2   __new__()構造器方法

該方法必須返回一個實例,因此更像一個構造器。可以用於根據條件確定是否返回實例。

def __new__(cls, *args, **kwargs)   #cls是當前正在實例化的類名, 由Python解釋器自動提供

       return object.__new__( cls, *args, **kwargs)  #可以return父類__new__()出來的實例

用於定製類

class RoundFloat(float):

def __new__(cls, val):

return super(RoundFloat, cls).__new__(cls, round(val, 2))

1.2.3   __del__()解構器方法

解構器是在類C 實例所有的引用都被清除掉後才被調用的,比如當引用計數已減少到0。

class C(P):

def __del__(self):         # "destructor" 解構器

P.__del__(self)   # 總是調用父類(或直接是object)的__del__方法

1.2.4   實例屬性

給一個與類屬性同名的實例屬性賦值,會隱藏類屬性。一旦刪除了這個實例屬性,類屬性又可見。因此不要使用實例屬性來修改類屬性,而是使用類屬性來修改自身。

1.2.5   type()和isinstance()內建函數

type()

       判斷type(1)==int

       生成新類X=type('X', (object,), dict(a=1,b=2,c=2)) #類名;基類;類內變量

                     # <class'__main__.X'>

       import types;type(1)==types.IntType #減少函數使用次數

isinstance()

       判斷是否爲類的實例,與type()的區別是isinstance()會認爲子類是一種父類類型,考慮繼承關係

       isinstance (a,str)

       isinstance (a,(str,int,list))#若是元組中一個,則返回True

1.3   繼承

①調用子類屬性,會覆蓋父類的同名屬性,包括__init__()特殊方法。若子類定義了__init__(),子類不會自動調用父類的__init__()。可以使用super()內建函數實現。

②在子類中調用父類的同名方法:

class C(P):

       def __init__(self):

          super(C,self).__init__()

def foo(self):

        P.foo(self)

c=C()

 

super()會找到父類構造器方法。不必給出父類名稱。

調用c.foo()

調用父類的未綁定方法,需傳入一個實例。

1.4   訪問限制

1.4.1   雙下劃線“__”

①實例的變量名如果以__開頭,就變成了一個私有變量(private),只有內部可以訪問,外部不能訪問。

②如果在類中有一個__XXX 屬性,它將不會被其子類中的__XXX屬性覆蓋。因爲解釋器將其改名爲_ClassName__XXX。

③以雙下劃線開頭,並且以雙下劃線結尾的,是特殊變量,特殊變量是可以直接訪問的,用戶不要定義。

1.4.2   單下劃線“_”

①一個下劃線開頭的實例變量名,外部可以訪問,但是按照約定不要隨意訪問。

②可以防止模塊的屬性被“fromMODULE import *”加載。

1.5   內建函數

issubclass(sub, sup)

判斷是否是子類或子孫類。sup可以是元組,有任意一個是父類,則返回Ture。當sub==sup時,返回True

isinstance(obj1,obj2)

判斷obj1是否是obj2的實例。obj2可以是元組

hasattr(obj, attr)

attr是字符串。返回布爾型。判斷對象是否有attr屬性

getattr(obj, attr [, default])

獲取對象的某屬性。若無則返回默認返回值default(未定義則返回AttributeError異常)

setattr(obj, attr)

設置或覆蓋對象的某個屬性

delattr(obj, attr)

從一個對象中刪除屬性

dir([object])

__dict__是dir()的子集。dir()會找到類對象或實例的全部屬性,包括從父類繼承的屬性。不會顯示定義在元中的類屬性; 作用在模塊上時,則顯示模塊的__dict__的內容;不帶參數時,則顯示調用者的局部變量.

vars(obj=None)

返回__dict__.。對象的屬性及其值的一個字典;如果沒有給出obj,vars()顯示局部命名空間字典(locals())

super(type[, obj])

返回此type 的父類。傳入type的實例obj,則綁定父類

1.6   包裝與授權

包裝:對一個已經存在的對象進行功能定製。

授權:包裝類的實例可以直接訪問被包裝對象的屬性,通過在包裝類中重寫__getattr__()方法。訪問屬性時先在實例屬性中查找,然後在類屬性中查找,最後通過__getattr__()查找屬性,可以寫做:

class Wrapper(object):

def __init__(self,obj):

    self. _wrappedObj=obj

def __getattr__(self, attr):

    return getattr(self._wrappedObj,attr)

wrappedComplex = Wrapper(3.5+4.2j)

wrappedComplex.real

1.7   高級特性

1.7.1   __slots__

動機:__dict__屬性跟蹤實例的所有屬性,即inst.foo 等價於inst.__dict__['foo']。但是字典佔用內存大,若類簡單而實例多,可定義__slots__替代__dict__,帶__slots__屬性的類定義不會存在__dict__,以節約內存。

在定義class的時候,定義一個特殊的__slots__類變量,可以限制該class實例能添加的屬性。

__slots__是一個序列對象(列表、元組、可迭代對象)。

__slots__定義的屬性僅對當前類實例起作用,對繼承的子類是不起作用的。

class C(object):

__slots__= ('attr1', 'attr2')

1.7.2   @property

property是getter setter deleter三者的集合。用於實現屬性的get和set方法。

class C(object):

    @property

    defname(self):

       return self._name

   @name.setter

    defname(self,value):

        ifnot isinstance(value, str):

           raise TypeError('Expected a string')

       self._name = value

   @name.deleter

    defname(self):

        raiseAttributeError("Can't delete attribute")

1.7.3   描述符

描述符是創建託管屬性的方法。描述符具有諸多用途:保護屬性不受修改、屬性類型檢查和自動更新某個依賴屬性的值等,是實現了__get__(),__set__()或__delete__()特殊方法的類,該類的實例對象通常是另一個類的類屬性。

只實現__get__方法的對象是非數據描述符,只能被讀取。而同時實現__get__和__set__的對象是數據描述符。

當使用實例對象訪問屬性時,都會調用__getattribute__()方法,該方法查找屬性的優先級如下:

類屬性à數據描述符à實例屬性à非數據描述符à__getattr__()方法

①在類屬性(包括祖先類)中查找數據描述符,如找到,則直接調用該數據描述符的__get__方法並將結果返回;

②若未找到,則在實例的__dict__中查找屬性;

③在類(包括祖先類)的__dict__屬性中查找非數據描述符

普通函數(包括函數、靜態/類方法)都是非數據描述符,可被實例屬性覆蓋。

       class C(object):

           def __init__(self, name):

               self._name=name

           def __get__(self, obj, typ=None):

               return self.name

           def __set__(self, obj, value):

               self._name=value

       class Test(object):

           name=C()

 

test=Test()

test.name='123'  # 調用__set__()方法

1.7.4   枚舉類

①Enum

from enum importEnum

       month=Enum('month',('JAY','FEB','MAR','APR'))

       print(month.JAY)      #返回month.JAY

       type(month.JAY)  # <enum 'month'>

       print(month.JAY.value)  #返回1。int,默認從1開始

       forname, member in Month.__members__.items(): #遍歷

           print(name, '=>', member, ',',member.value) #第一個是JAY => month.JAY, 1

②@unique

檢查保證沒有重複值.

   @unique

class Weekday(Enum):

    Sun = 0 # Sun的value被設定爲0

    Mon = 1

    Tue = 2

    Wed = 3

Weekday.Tue     #Weekday.Tue

Weekday['Tue']   #Weekday.Tue

Weekday(2)      #Weekday.Tue

1.7.5   定製類

__str__():

       在類中實現該方法,return一個自定義的顯示字符串,調用print()和str()時將會顯示該字符串。

__repr__():

       交互界面直接輸入變量名,輸出的結果是調用repr()的結果,用於調試服務。

       在類中可以直接寫__repr__ = __str__

__iter__():

返回一個迭代對象,使對象可以用於iter()內建函數。不斷調用該迭代對象的__next__()方法,返回下一個值,直到StopIteration錯誤時退出循環。對於自定義的迭代器,只需返回自身self。

__next__():

       實現該方法就是一個迭代器。

       def __next__(self):

        self.a, self.b =self.b, self.a + self.b # 計算下一個值

        if self.a > 100000:# 退出循環的條件

            raiseStopIteration()

        return self.a # 返回下一個值

__getitem__(self, n):

       使能夠像list那樣按照下標取出下標爲n的元素。

__setitem__( self, n):

       把對象視作list或dict來對集合賦值。

__delitem__( self, n):

       用於刪除某個元素。

__getattr__(self, attr):

當調用實例的不存在的屬性,將嘗試調用該方法,動態返回一個值。若嘗試該函數和實例中未定義的其他屬性,則會返回None。對於其他未定義的屬性,可以拋出異常。raise AttributeError('xxxxxxxxxx').

__call__():

       使實例可以像函數一樣,成爲一個可調用callable對象。可以定義參數,調用時執行該特殊方法下的內容。

       如c=C(); c() #將執行__call__()。

       callable()內置函數可以判斷是否是可調用對象。

__nonzero__(self):用於內建函數bool(), 定義轉爲布爾值的方法。

__len__(self):用於內建函數len(),求取對象“長度”。

數值定製用的特殊方法:__add__(self, other)、__mul__(self, num):
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章