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):