Python語言基礎07-面向對象編程基礎

来源:https://www.cnblogs.com/along21/archive/2019/11/18/11886126.html
-Advertisement-
Play Games

本文收錄在Python從入門到精通系列文章系列 1. 瞭解面對對象編程 活在當下的程式員應該都聽過"面向對象編程"一詞,也經常有人問能不能用一句話解釋下什麼是"面向對象編程",我們先來看看比較正式的說法。 "把一組數據結構和處理它們的方法組成對象(object),把相同行為的對象歸納為類(class ...


本文收錄在Python從入門到精通系列文章系列

1. 瞭解面對對象編程

  活在當下的程式員應該都聽過"面向對象編程"一詞,也經常有人問能不能用一句話解釋下什麼是"面向對象編程",我們先來看看比較正式的說法。

  "把一組數據結構和處理它們的方法組成對象(object),把相同行為的對象歸納為類(class),通過類的封裝(encapsulation)隱藏內部細節,通過繼承(inheritance)實現類的特化(specialization)和泛化(generalization),通過多態(polymorphism)實現基於對象類型的動態分派。"

  這樣一說是不是更不明白了。所以我們還是看看更通俗易懂的說法,請看下圖:

  之前我們說過"程式是指令的集合",我們在程式中書寫的語句在執行時會變成一條或多條指令然後由CPU去執行。當然為了簡化程式的設計,我們引入了函數的概念,把相對獨立且經常重覆使用的代碼放置到函數中,在需要使用這些功能的時候只要調用函數即可;如果一個函數的功能過於複雜和臃腫,我們又可以進一步將函數繼續切分為子函數來降低系統的複雜性。

  但是說了這麼多,不知道大家是否發現,所謂編程就是程式員按照電腦的工作方式控制電腦完成各種任務。但是,電腦的工作方式與正常人類的思維模式是不同的,如果編程就必須得拋棄人類正常的思維方式去迎合電腦,編程的樂趣就少了很多,"每個人都應該學習編程"這樣的豪言壯語就只能說說而已。當然,這些還不是最重要的,最重要的是當我們需要開發一個複雜的系統時,代碼的複雜性會讓開發和維護工作都變得舉步維艱,所以在上世紀60年代末期,"軟體危機"、"軟體工程"等一系列的概念開始在行業中出現。

  當然,程式員圈子內的人都知道,現實中並沒有解決上面所說的這些問題的"銀彈",真正讓軟體開發者看到希望的是上世紀70年代誕生的Smalltalk編程語言中引入的面向對象的編程思想(面向對象編程的雛形可以追溯到更早期的Simula語言)。按照這種編程理念,程式中的數據和操作數據的函數是一個邏輯上的整體,我們稱之為“對象”,而我們解決問題的方式就是創建出需要的對象並向對象發出各種各樣的消息,多個對象的協同工作最終可以讓我們構造出複雜的系統來解決現實中的問題。

  說明: 當然面向對象也不是解決軟體開發中所有問題的最後的“銀彈”,所以今天的高級程式設計語言幾乎都提供了對多種編程範式的支持,Python也不例外。

 

2. 類和對象

  簡單的說,類是對象的藍圖和模板,而對象是類的實例。這個解釋雖然有點像用概念在解釋概念,但是從這句話我們至少可以看出,類是抽象的概念,而對象是具體的東西。在面向對象編程的世界中,一切皆為對象,對象都有屬性和行為,每個對象都是獨一無二的,而且對象一定屬於某個類(型)。當我們把一大堆擁有共同特征的對象靜態特征(屬性)和動態特征(行為)都抽取出來後,就可以定義出一個叫做“類”的東西。

2.1 定義類

  在Python中可以使用class關鍵字定義類,然後在類中通過之前學習過的函數來定義方法,這樣就可以將對象的動態特征描述出來,代碼如下所示。

class Student(object):

    # __init__是一個特殊方法用於在創建對象時進行初始化操作
    # 通過這個方法我們可以為學生對象綁定name和age兩個屬性
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def study(self, course_name):
        print('%s正在學習%s.' % (self.name, course_name))

    # PEP 8要求標識符的名字用全小寫多個單詞用下劃線連接
    # 但是部分程式員和公司更傾向於使用駝峰命名法(駝峰標識)
    def watch_movie(self):
        if self.age < 18:
            print('%s只能觀看《熊出沒》.' % self.name)
        else:
            print('%s正在觀看島國愛情大電影.' % self.name)

說明: 寫在類中的函數,我們通常稱之為(對象的)方法,這些方法就是對象可以接收的消息。

 

2.2 創建和使用對象

  當我們定義好一個類之後,可以通過下麵的方式來創建對象並給對象發消息。

def main():
    # 創建學生對象並指定姓名和年齡
    stu1 = Student('along', 66)
    # 給對象發study消息
    stu1.study('Python從入門到精通系列文章總目錄')
    # 給對象發watch_av消息
    stu1.watch_movie()
    stu2 = Student('小黑', 15)
    stu2.study('數學')
    stu2.watch_movie()

main()

 

3. 訪問可見性問題

  對於上面的代碼,有C++、Java、C#等編程經驗的程式員可能會問,我們給Student對象綁定的name和age屬性到底具有怎樣的訪問許可權(也稱為可見性)。因為在很多面向對象編程語言中,我們通常會將對象的屬性設置為私有的(private)或受保護的(protected),簡單的說就是不允許外界訪問,而對象的方法通常都是公開的(public),因為公開的方法就是對象能夠接受的消息。在Python中,屬性和方法的訪問許可權只有兩種,也就是公開的和私有的,如果希望屬性是私有的,在給屬性命名時可以用兩個下劃線作為開頭,下麵的代碼可以驗證這一點。

class Test:

    def __init__(self, foo):
        self.__foo = foo

    def __bar(self):
        print(self.__foo)
        print('__bar')


def main():
    test = Test('hello')
    # AttributeError: 'Test' object has no attribute '__bar'
    # test.__bar()
    # AttributeError: 'Test' object has no attribute '__foo'
    # print(test.__foo)


if __name__ == "__main__":
    main()

   但是,Python並沒有從語法上嚴格保證私有屬性或方法的私密性,它只是給私有的屬性和方法換了一個名字來妨礙對它們的訪問,事實上如果你知道更換名字的規則仍然可以訪問到它們,下麵的代碼就可以驗證這一點。之所以這樣設定,可以用這樣一句名言加以解釋,就是"We are all consenting adults here"。因為絕大多數程式員都認為開放比封閉要好,而且程式員要自己為自己的行為負責。

class Test:

    def __init__(self, foo):
        self.__foo = foo

    def __bar(self):
        print(self.__foo)
        print('__bar')


def main():
    test = Test('hello')
    test._Test__bar()
    print(test._Test__foo)


if __name__ == "__main__":
    main()

  在實際開發中,我們並不建議將屬性設置為私有的,因為這會導致子類無法訪問(後面會講到)。所以大多數Python程式員會遵循一種命名慣例就是讓屬性名以單下劃線開頭來表示屬性是受保護的,本類之外的代碼在訪問這樣的屬性時應該要保持慎重。這種做法並不是語法上的規則,單下劃線開頭的屬性和方法外界仍然是可以訪問的,所以更多的時候它是一種暗示或隱喻.

 

4. 面向對象的支柱

  面向對象有三大支柱:封裝、繼承和多態。後面兩個概念在下一篇中進行詳細的說明,這裡我們先說一下什麼是封裝。我自己對封裝的理解是"隱藏一切可以隱藏的實現細節,只向外界暴露(提供)簡單的編程介面"。我們在類中定義的方法其實就是把數據和對數據的操作封裝起來了,在我們創建了對象之後,只需要給對象發送一個消息(調用方法)就可以執行方法中的代碼,也就是說我們只需要知道方法的名字和傳入的參數(方法的外部視圖),而不需要知道方法內部的實現細節(方法的內部視圖)。

 

5. 練習

練習1:定義一個類描述數字時鐘

參考答案:

from time import sleep

class Clock(object):
    """數字時鐘"""

    def __init__(self, hour=0, minute=0, second=0):
        """初始化方法

        :param hour: 時
        :param minute: 分
        :param second: 秒
        """
        self._hour = hour
        self._minute = minute
        self._second = second

    def run(self):
        """走字"""
        self._second += 1
        if self._second == 60:
            self._second = 0
            self._minute += 1
            if self._minute == 60:
                self._minute = 0
                self._hour += 1
                if self._hour == 24:
                    self._hour = 0

    def show(self):
        """顯示時間"""
        return '%02d:%02d:%02d' % \
               (self._hour, self._minute, self._second)


def main():
    clock = Clock(23, 59, 58)
    while True:
        print(clock.show())
        sleep(1)
        clock.run()


if __name__ == '__main__':
    main()

 

輸出結果:

23:59:58
23:59:59
00:00:00
... ...

 

練習2:定義一個類描述平面上的點並提供移動點和計算到另一個點距離的方法

參考答案:

from math import sqrt

class Point(object):

    def __init__(self, x=0, y=0):
        """初始化方法
        
        :param x: 橫坐標
        :param y: 縱坐標
        """
        self.x = x
        self.y = y

    def move_to(self, x, y):
        """移動到指定位置
        
        :param x: 新的橫坐標
        "param y: 新的縱坐標
        """
        self.x = x
        self.y = y

    def move_by(self, dx, dy):
        """移動指定的增量
        
        :param dx: 橫坐標的增量
        "param dy: 縱坐標的增量
        """
        self.x += dx
        self.y += dy

    def distance_to(self, other):
        """計算與另一個點的距離
        
        :param other: 另一個點
        """
        dx = self.x - other.x
        dy = self.y - other.y
        return sqrt(dx ** 2 + dy ** 2)

    def __str__(self):
        return '(%s, %s)' % (str(self.x), str(self.y))


def main():
    p1 = Point(1, 2)
    p2 = Point(2, 1)
    print(p1)
    print(p2)
    p2.move_by(-1, 2)
    print(p2)
    print(p1.distance_to(p2))

輸出結果:

(1, 2)
(2, 1)
(1, 3)
1.0

  說明: 本章中的插圖來自於Grady Booch等著作的《面向對象分析與設計》一書,該書是講解面向對象編程的經典著作,有興趣的讀者可以購買和閱讀這本書來瞭解更多的面向對象的相關知識。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 設計模式--觀察者模式 1、觀察者模式 觀察者模式:定義對象間一種一對多的依賴關係,當一個對象狀態發生變化時,所有依賴於它的對象都得到通知,並被自動更新。 2、觀察者模式的結構 角色 主題(Subject):主題是一個介面,該介面規定了具體主題需要實現的方法,比如添加,刪除觀察者以及通知觀察者的方法 ...
  • 裝飾器模式--裝飾模式 1、裝飾模式 裝飾模式:動態的給對象添加一些額外的職責,例如,給相片加各種不同的相框(相框就是裝飾器)。 2、裝飾模式的結構 角色 抽象組件(Component): 抽象組件定義了需要進行裝飾的方法,也就是“被裝飾者”角色; 具體組件(ConcreteComponent): ...
  • 系統分析師 軟體水平考試(高級) 開篇 前言 時隔一年,我開始了系統分析師的博客寫作。回過頭翻看一下,一年前的系統架構設計師系列的第一篇博客 需求理論,還是比較有感觸的。 其實系統分析師的考試早在上邊年五月份就參與了,也在六月份就知道自己通過了考試。但是一方面系統分析師與系統架構設計師有很多內容上的 ...
  • 一、安裝Redis集群 安裝步驟參照網上教程,Mac安裝步驟參照https://github.com/muyl/mac docker redis cluster 二、創建SpringBoot工程 1. 創建Redis配置類 2. SpringBoot屬性文件 3. SpringBoot啟動類 4. ...
  • 後補 ...
  • 1、Java代碼監控 JDK提供java.lang.management包, 其實就是基於JMX技術規範,提供一套完整的MBean,動態獲取JVM的運行時數據,達到監控JVM性能的目的。 代碼地址 "https://github.com/AganRun/Learn/tree/master/Java/ ...
  •  很幸運參與零售雲快消平臺的公有雲搭建及孵化項目。零售雲快消平臺源於零售雲家電3C平臺私有項目,是與公司業務強耦合的。為了適用於全場景全品類平臺,集團要求項目平臺化,我們搶先並承擔了此任務。並由我來主要負責平臺建設及項目落地。  今天講解在零售雲快消平臺中使用的圖片服務FastD ...
  • 目錄: 一、列表推導式 二、生成器表達式 三、集合生成器 四、生成器面試題 五、解耦簡單介紹 六、函數遞歸相關 一、列表推導式 需求:將[1,3,5]中的每個元素平方 正常思路: 1 new_list = [] 2 for i in [1,3,5]: 3 new_list.append(i*i) 4 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...