NOTE:文章中的代碼縮進不知道怎么搞,直接粘貼使用會報錯
面向對象編程(Object Oriented Programming簡稱OOP)
- OOP把對象作為程序的基本單元,一個對象包含了數據和操作數據的函數。
- 面向對象的設計思想是抽象出Class,根據Class創建Instance
面向對象的三大特點:
- 數據封裝
- 繼承
- 多態
類(Class)和實例(Instance)
- 類是抽象的模板
- 實例是根據類創建出來的一個個具體的"對象"
note:每個對象都擁有相同的方法,但各自的數據可能不同 - 定義類通過
Class
關鍵字:
class Student(object):
pass
- 類名是大寫字母開頭的單詞,
()
里表示該類是從哪個類繼承下來的,沒有合適的類就用object
類,這是所有類最終都會繼承的類
- 創建實例是通過類名+()實現的:
>>> bart = Student()
- 類可以起到模板的作用
可以在創建實例的時候,把一些我們認為必須綁定的屬性強制填寫進去,通過定義一個特殊的__init__
方法來實現:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
note:__init__
方法的第一個參數永遠是self
,表示創建的實例本身,但是在調用是不用傳遞該參數。除此之外類的方法和普通函數沒有什么區別,可以使用默認參數、可變參數、關鍵字參數和命名關鍵字參數
數據封裝
- 實例本身就擁有數據,要訪問這些數據,沒有必要從外面的函數去訪問,直接在類的內部定義訪問數據的函數,這樣,就把“數據”給封裝起來了。
- 這些封裝數據的函數是和類本身是關聯起來的,我們稱之為類的方法
- 定義方法
除了第一個參數是self
外,其他和普通函數一樣
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
- 調用方法
只需要在實例變量上直接調用,除了self
不用傳遞,其他參數正常傳入:
>>> bart.print_score()
Bart Simpson: 59
數據封裝的優勢:
- 調用容易,不用知道內部實現的細節
- 可以給類增加新的方法
訪問限制
- 要讓內部屬性不被外部訪問,可以把屬性的名稱前加上兩個下劃線
__
,實例的變量名如果以__
開頭,就變成了一個私有變量(private),只有內部可以訪問,外部不能訪問
note:__xxx__
是特殊變量,可以直接訪問,不是private變量,注意區分
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
- 要想外部訪問內部變量,可以通過給類增加方法來實現
繼承和多態
在OOP程序設計中,當我們定義一個class的時候,可以從某個現有的class繼承,新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Base class、Super class)
- 繼承的好處:
- 子類獲得了父類的全部功能
- 我們對代碼做一點改進,子類和父類都存在相同的方法時,之類的方法會覆蓋父類的方法,這就是多態
- 多態的好處(“開閉原則”):
- 對擴展開放:允許新增子類
- 對修改封閉:不需要修改依賴父類的任何函數
- 動態語言的“鴨子類型”
不要求嚴格的繼承體系,一個對象只要“看起來像鴨子,走起路來像鴨子”,那它就可以被看做是鴨子
也就是不同的對象只要有相同的方法,那么就可以認為是一種“類型”
獲取對象信息
type()
-
isinstance()
返回值是True或者False -
dir()
獲得一個對象的所有屬性和方法
- 類似
__xxx__
的屬性和方法在Python中都是有特殊用途的
-
getattr()
、setattr()
、hasattr()
- 對于
getattr()
可以傳入一個default參數,如果屬性不存在,就返回默認值
>>> getattr(obj, 'z', 404) # 獲取屬性'z',如果不存在,返回默認值404
實例屬性和類屬性
- 類的屬性直接在Class中定義,該屬性歸該類所有,因此所有的實例都可以訪問類的屬性
- 千萬不要把實例屬性和類屬性使用相同的名字,因為相同名稱的實例屬性將屏蔽掉類屬性