為什么要面向對象編程?
偉大的領袖毛澤東曾說過:編程最大的敵人是重復。
- 最開始,在程序中寫的一條條語句,在執行的時候會變成一條條指令交給CPU執行。這就是**“程序是指令的集合”** 。
- 為了簡化程序的設計,引入了函數的概念。把相對獨立、經常重復使用的代碼放到函數中。當一個函數的語句過多的時候,我們就給它拆分成一個個子函數。函數式編程
- 單當程序到極度復雜的時候,單純的函數無法滿足維護、開發、升級的工作。于是有人提出面向對象編程。推翻了以 小塊函數為單位的思想,而是把數據+函數組成的對象為最小單位。
什么是面向對象編程?
你肯定聽過,面向對象的三大要素:封裝、繼承和多態。
正式的說法:把一組數據結構和處理他們的方法組成對象 (object
), 把相同行為的對象歸納為類 (class
), 通過類的封裝 ( encapsulation
)隱藏內部細節,通過繼承 (inheritance
)實現類的特殊化 (specialization
)和 廣泛化 (generalization
), 通過多態 (polymorphism
)實現基于對象類型的動態分派。
是不是很難懂?說起來也拗口,沒有基礎的人根本看不懂。
這樣講吧,我們在出生的時候就被賦予一個類 (人),我們自身有一些屬性 (身高,體重 ,年齡),還有一些技能,也就是方法 ( 吃飯 、呼吸 )
- 封裝:你今年多少歲了,你只需要告訴別人結果,不用告訴人你是怎么算的,不需要知道內部實現細節。這就是封裝。
- 繼承:我們之所以有這些屬性、技能,是因為我們的父母也是人,我們是遺傳基因得來的。
- 多態:一些人演化出來特有技能,比如倒立洗頭,泡妹。但有一些人不會。
說了這么多,面向對象是一種思想,范式,約定。你也可以不這么做,也能寫代碼,只是可能,當應用復雜到一定程度,只有你看的懂,無法同其他人交流。
面向過程與面向對象對比
假設我們要處理學生的成績表,打印一個學生的成績: 姓名 + 分數
,面向過程的程序可以用一個dict表示:
std1 = { 'name': 'Michael', 'score': 98 }
std2 = { 'name': 'Bob', 'score': 81 }
函數式編程的思想就是,直接思考程序的執行 , 面向過程
。
def print_score(std):print(f'{std[name]} : {std[score]}')
面向對象的編程思想 ,則首先思考的是 std 應該是一個 學生對象,有 姓名(name) 和 分數 (score) 這兩個屬性。有一個技能打印成績 print_score() , 如果要打印成績需要,先創建一個學生,然后告訴學生我要打印成績。
class Student(object):def __init__(self, name, score):self.name = nameself.score = scoredef print_score(self):print(f'{std[name]} : {std[score]}')
zhangsan = Student('張三', 59)
lisi = Student('李四', 87)
zhangsan.print_score()
lisi.print_score()
類的定義和實例
下面是一個類
class Student(object):def __init__(self, name, score):self.name = nameself.score = scoredef print_score(self):print(f'{std[name]} : {std[score]}')
__init__
是一個特殊方法用于在創建對象時進行初始化操作 , 為學生對象綁定 name
和 score
兩個屬性
- 注意:特殊方法“
__init__
”前后分別有兩個下劃線!!!- 注意到
__init__
方法的第一個參數永遠是self
,表示創建的實例本身,因此,在__init__
方法內部,就可以把各種屬性綁定到self
,因為self
就指向創建的實例本身。- 如果有了
__init__
方法,在創建實例的時候,就不能傳入空的參數了,必須傳入與__init__
方法匹配的參數,但self
不需要傳,Python解釋器自己會把實例變量傳進去:
def print_score(self)
和普通的函數相比,在類中定義的函數只有一點不同,就是第一個參數永遠是實例變量self
,但是調用時,不用傳遞該參數。