1. 程式人生 > >聰哥哥教你學Python之面向物件程式設計

聰哥哥教你學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的開發經驗,很容易學習。