聰哥哥教你學Python之面向物件程式設計
什麼是面向物件程式設計?
引用百度百科解釋:
面向物件程式設計(Object Oriented Programming)作為一種新方法,其本質是以建立模型體現出來的抽象思維過程和麵向物件的方法。模型是用來反映現實世界中事物特徵的。任何一個模型都不可能反映客觀事物的一切具體特徵,只能對事物特徵和變化規律的一種抽象,且在它所涉及的範圍內更普遍、更集中、更深刻地描述客體的特徵。通過建立模型而達到的抽象是人們對客體認識的深化。
既然說到面向物件,也就不能不提面向過程。
那麼是什麼是面向過程呢?
“面向過程”(Procedure Oriented)是一種以過程為中心的程式設計思想。“面向過程”也可稱之為“面向記錄”程式設計思想,他們不支援豐富的“
或許還會有人問,面向過程和麵向物件的區別是什麼?
這個聰哥哥我也不知道,所以參考一位博友朋友所說的:
面向過程就是分析出解決問題所需要的步驟,然後用函式把這些步驟一步一步實現,使用的時候一個一個依次呼叫就可以了;
面向物件是把構成問題事務分解成各個物件,建立物件的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為。
可以拿生活中的例項來理解面向過程與面向物件,例如五子棋,面向過程的設計思路就是首先分析問題的步驟:
1、開始遊戲,2、黑子先走,3、繪製畫面,4、判斷輸贏,5、輪到白子,6、繪製畫面,7、判斷輸贏,8、返回步驟2,9、輸出最後結果。把上面每個步驟用不同的方法來實現。
如果是面向物件的設計思想來解決問題。面向物件的設計則是從另外的思路來解決問題。整個五子棋可以分為:
1、黑白雙方,這兩方的行為是一模一樣的,2、棋盤系統,負責繪製畫面,3、規則系統,負責判定諸如犯規、輸贏等。第一類物件(玩家物件)負責接受使用者輸入,並告知第二類物件(棋盤物件)棋子佈局的變化,棋盤物件接收到了棋子的變化就要負責在螢幕上面顯示出這種變化,同時利用第三類物件(規則系統)來對棋局進行判定。
可以明顯地看出,面向物件是以功能來劃分問題,而不是步驟。同樣是繪製棋局,這樣的行為在面向過程的設計中分散在了多個步驟中,很可能出現不同的繪製版本,因為通常設計人員會考慮到實際情況進行各種各樣的簡化。而面向物件的設計中,繪圖只可能在棋盤物件中出現,從而保證了繪圖的統一。
面向物件和麵向過程程式設計的優缺點是什麼?
面向過程
優點:效能比面向物件高,因為類呼叫時需要例項化,開銷比較大,比較消耗資源,比如微控制器、嵌入式開發、Linux/Unix等一般採用面向過程開發,效能是最重要的因素。
缺點:沒有面向物件易維護、易複用、易擴充套件
面向物件
優點:易維護、易複用、易擴充套件,由於面向物件有封裝、繼承、多型性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易於維護
缺點:效能比面向過程低
今天聰哥哥我主要講的是類和例項、訪問限制、繼承和多型、獲取物件資訊、例項屬性和類屬性等五個方面。
有一定程式語言基礎的朋友們,可以聯絡到自身經常用到的程式語言,通過對比進行學習,同時也可以溫習。
一、類和例項
面向物件最重要的概念就是類(Class)和例項(Instance),必須牢記類是抽象的模板,比如Student類,而例項是根據類創建出來的一個個具體的“物件”,每個物件都擁有相同的方法,但各自的資料可能不同。
示例一:
# -*- coding: utf-8 -*-
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def get_grade(self):
if self.score >= 90:
return 'A'
elif self.score >= 60:
return 'B'
else:
return 'C'
lisa = Student("Lisa",100)
bart = Student("Bart",50)
print(lisa.name,lisa.get_grade())
print(bart.name,bart.get_grade())
聰哥哥有話說:
(1)類是建立例項的模板,而例項則是一個一個具體的物件,各個例項擁有的資料都互相獨立,互不影響;
(2)方法就是與例項繫結的函式,和普通函式不同,方法可以直接訪問例項的資料;
(3)通過在例項上呼叫方法,我們就直接操作了物件內部的資料,但無需知道方法內部的實現細節。
二、訪問限制
在Class內部,可以有屬性和方法,而外部程式碼可以通過直接呼叫例項變數的方法來操作資料,這樣,就隱藏了內部的複雜邏輯。
示例一(如果要讓內部屬性不被外部訪問,可以把屬性的名稱前加上兩個下劃線__
,在Python中,例項的變數名如果以__
開頭,就變成了一個私有變數(private),只有內部可以訪問,外部不能訪問,所以,我們把Student類改一改):
# -*- coding: utf-8 -*-
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))
bart = Student("聰哥哥",100)
print(bart.__name)
改完後,對於外部程式碼來說,沒什麼變動,但是已經無法從外部訪問例項變數.__name
和例項變數.__score
了
結果如圖:
三、繼承和多型
在OOP程式設計中,當我們定義一個class的時候,可以從某個現有的class繼承,新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Base class、Super class)。
繼承的好處是不言而喻的,繼承是為了複用,複用是為了降低程式碼冗餘。
來一段示例說明,比如動物類繼承示例
示例一:
# -*- coding: utf-8 -*-
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
def eat(self):
print('Eating meat...')
class Cat(Animal):
pass
dog = Dog()
dog.run()
dog.eat()
cat = Cat()
cat.run()
聰哥哥有話說:
繼承可以把父類的所有功能都直接拿過來,這樣就不必重零做起,子類只需要新增自己特有的方法,也可以把父類不適合的方法覆蓋重寫。
四、獲取物件資訊
當我們拿到一個物件的引用時,如何知道這個物件是什麼型別、有哪些方法呢?
基本型別都可以用type()來判斷,例如:
# -*- coding: utf-8 -*-
print(type(1234))
如圖:
繼承關係可以使用isinstance()
例如:
# -*- coding: utf-8 -*-
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
def eat(self):
print('Eating meat...')
class Cat(Animal):
pass
dog = Dog()
cat = Cat()
print(isinstance(cat,Cat))
結果如:
如果要獲得一個物件的所有屬性和方法,可以使用dir()
函式,它返回一個包含字串的list,比如,獲得一個str物件的所有屬性和方法:
# -*- coding: utf-8 -*-
print(dir("ABC"))
結果如圖:
聰哥哥有話說:
通過內建的一系列函式,我們可以對任意一個Python物件進行剖析,拿到其內部的資料。要注意的是,只有在不知道物件資訊的時候,我們才會去獲取物件資訊。
五、例項屬性和類屬性
由於Python是動態語言,根據類建立的例項可以任意繫結屬性。
或許有哪位小哥哥或是小姐姐會問什麼是動態語言,然後接著又會問,有動態語言,就有與之相反的靜態語言,那麼什麼是靜態語言。
最後產生的問題就是什麼是動態語言?什麼是靜態語言?動態語言和靜態語言的區別?動態語言和靜態語言的優劣?
問題一個一個來回答。
問:什麼是動態語言?
答:引用百度百科:動態語言,是指程式在執行時可以改變其結構:新的函式可以被引進,已有的函式可以被刪除等在結構上的變化,型別的檢查是在執行時做的,優點為方便閱讀,清晰明瞭,缺點為不方便除錯。
問:什麼是靜態語言?
答:靜態語言是在編譯時變數的資料型別即可確定的語言,多數靜態型別語言要求在使用變數之前必須宣告資料型別。
或許有人說,我聽不懂這麼官方的說辭。
那好,接下來由聰哥哥來通俗解答:動態語言不需要編譯即可執行,而靜態語言需要編譯後才能執行(關於動態語言和靜態語言的區別,這個也是答案)。
問:動態語言和靜態語言的優劣比較?
答:
靜態語言的優勢:
(1)由於型別的強制宣告,使得IDE有很強的程式碼感知能力,故,在實現複雜的業務邏輯、開發大型商業系統、以及那些生命週期很長的應用中,依託IDE對系統的開發很有保障;
(2)由於靜態語言相對比較封閉,使得第三方開發包對程式碼的侵害性可以降到最低;
(3)程式碼執行速度快。
靜態語言的劣勢:
程式碼不夠簡潔。
動態語言的優勢:
(1)思維不受束縛,可以任意發揮,把更多的精力放在產品本身上;
(2)集中思考業務邏輯實現,思考過程即實現過程。
動態語言的劣勢:
不方便除錯,命名容易混淆。
程式碼示例:
# -*- coding: utf-8 -*-
class Student(object):
name = '聰哥哥'
s = Student() #例項
print(s.name)
聰哥哥有話說:
(1)例項屬性屬於各個例項所有,互不干擾;
(2)類屬性屬於類所有,所有例項共享一個屬性;
(3)不要對例項屬性和類屬性使用相同的名字,否則將產生難以發現的錯誤。
小結:
聰哥哥有話說,對於本章學習,有一定的程式設計經驗人士學習起來,特別是接觸過面向物件這個概念,或者是有Java的開發經驗,很容易學習。