固然,若是不支持python繼承,語言特性就不值得稱爲「類」。派生類定義的語法以下所示:html
<statement-1> . . . <statement-N>
名稱 BaseClassName 必須定義於包含派生類定義的做用域中。 也容許用其餘任意表達式代替基類名稱所在的位置。 這有時也可能會用得上,例如,當基類定義在另外一個模塊中的時候:python
class DerivedClassName(modname.BaseClassName):
派生類定義的執行過程與基類相同。 當構造類對象時,基類會被記住。 此信息將被用來解析屬性引用:若是請求的屬性在類中找不到,搜索將轉往基類中進行查找。 若是基類自己也派生自其餘某個類,則此規則將被遞歸地應用。nginx
派生類的實例化沒有任何特殊之處: DerivedClassName() 會建立該類的一個新實例。 方法引用將按如下方式解析:搜索相應的類屬性,若有必要將按基類繼承鏈逐步向下查找,若是產生了一個函數對象則方法引用就生效。程序員
派生類可能會重載其基類的方法。 由於方法在調用同一對象的其餘方法時沒有特殊權限,調用同一基類中定義的另外一方法的基類方法最終可能會調用覆蓋它的派生類的方法。 (對 C++ 程序員的提示:Python 中全部的方法實際上都是 virtual 方法。)算法
在派生類中的重載方法實際上可能想要擴展而非簡單地替換同名的基類方法。 有一種方式能夠簡單地直接調用基類方法:即調用 BaseClassName.methodname(self, arguments)。 有時這對客戶端來講也是有用的。 (請注意僅當此基類可在全局做用域中以 BaseClassName 的名稱被訪問時方可以使用此方式。)緩存
Python有兩個內置函數可被用於繼承機制:app
使用 isinstance() 來檢查一個實例的類型: isinstance(obj, int) 僅會在 obj.__class__ 爲 int 或某個派生自 int 的類時爲 True。
使用 issubclass() 來檢查類的繼承關係: issubclass(bool, int) 爲 True,由於 bool 是 int 的子類。 可是,issubclass(float, int) 爲 False,由於 float 不是 int 的子類。ide
多重繼承函數
class DerivedClassName(Base1, Base2, Base3): <statement-1> . . . <statement-N>
對於多數應用來講,在最簡單的狀況下,你能夠認爲搜索從父類所繼承屬性的操做是深度優先、從左至右的,當層次結構中存在重疊時不會在同一個類中搜索兩次。 所以,若是某一屬性在 DerivedClassName 中未找到,則會到 Base1 中搜索它,而後(遞歸地)到 Base1 的基類中搜索,若是在那裏未找到,再到 Base2 中搜索,依此類推。spa
真實狀況比這個更復雜一些;方法解析順序會動態改變以支持對 super() 的協同調用。 這種方式在某些其餘多重繼承型語言中被稱爲後續方法調用,它比單繼承型語言中的 super 調用更強大。
動態改變順序是有必要的,由於全部多重繼承的狀況都會顯示出一個或更多的菱形關聯(即至少有一個父類可經過多條路徑被最底層類所訪問)。 例如,全部類都是繼承自 object,所以任何多重繼承的狀況都提供了一條以上的路徑能夠通向 object。 爲了確保基類不會被訪問一次以上,動態算法會用一種特殊方式將搜索順序線性化, 保留每一個類所指定的從左至右的順序,只調用每一個父類一次,而且保持單調(即一個類能夠被子類化而不影響其父類的優先順序)。 總而言之,這些特性使得設計具備多重繼承的可靠且可擴展的類成爲可能。
私有變量
那種僅限從一個對象內部訪問的「私有」實例變量在 Python 中並不存在。 可是,大多數 Python 代碼都遵循這樣一個約定:帶有一個下劃線的名稱 (例如 _spam) 應該被看成是 API 的非僅供部分 (不管它是函數、方法或是數據成員)。 這應當被視爲一個實現細節,可能不經通知即加以改變。
因爲存在對於類私有成員的有效使用場景(例如避免名稱與子類所定義的名稱相沖突),所以存在對此種機制的有限支持,稱爲 名稱改寫。 任何形式爲 __spam 的標識符(至少帶有兩個前綴下劃線,至多一個後綴下劃線)的文本將被替換爲 _classname__spam,其中 classname 爲去除了前綴下劃線的當前類名稱。 這種改寫不考慮標識符的句法位置,只要它出如今類定義內部就會進行。
名稱改寫有助於讓子類重載方法而不破壞類內方法調用。例如:
def __init__(self, iterable): self.items_list = [] self.__update(iterable) def update(self, iterable): for item in iterable: self.items_list.append(item) __update = update # private copy of original update() method class MappingSubclass(Mapping): def update(self, keys, values): # provides new signature for update() # but does not break __init__() for item in zip(keys, values): self.items_list.append(item)
上面的示例即便在 MappingSubclass 引入了一個 __update 標識符的狀況下也不會出錯,由於它會在 Mapping 類中被替換爲 _Mapping__update 而在 MappingSubclass 類中被替換爲 _MappingSubclass__update。
請注意,改寫規則的設計主要是爲了不意外衝突;訪問或修改被視爲私有的變量仍然是可能的。這在特殊狀況下甚至會頗有用,例如在調試器中。
請注意傳遞給 exec() 或 eval() 的代碼不會將發起調用類的類名視做當前類;這相似於 global 語句的效果,所以這種效果僅限於同時通過字節碼編譯的代碼。 一樣的限制也適用於 getattr(), setattr() 和 delattr(),以及對於 dict 的直接引用。
雜項說明
有時會須要使用相似於 Pascal 的「record」或 C 的「struct」這樣的數據類型,將一些命名數據項捆綁在一塊兒。 這種狀況適合定義一個空類:
pass john = Employee() # Create an empty employee record # Fill the fields of the record john.name = 'John Doe' john.dept = 'computer lab' john.salary = 1000
一段須要特定抽象數據類型的 Python 代碼每每能夠被傳入一個模擬了該數據類型的方法的類做爲替代。 例如,若是你有一個基於文件對象來格式化某些數據的函數,你能夠定義一個帶有 read() 和 readline() 方法從字符串緩存獲取數據的類,並將其做爲參數傳入。
實例方法對象也具備屬性: m.__self__ 就是帶有 m() 方法的實例對象,而 m.__func__ 則是該方法所對應的函數對象。