# 面向對象編程(OOP)
> 原文: [https://javabeginnerstutorial.com/python-tutorial/object-oriented-programming-oop/](https://javabeginnerstutorial.com/python-tutorial/object-oriented-programming-oop/)
現在,我們進行了面向對象的編程。 曾經有過這樣一種炒作:每種語言都是圍繞對象設計的,而 Python 開發人員 Guido van Rossum 認為“為什么不呢?” 并添加了類以支持面向對象的開發。 一些 python 傳福音者認為這是一個錯誤的決定,有些認為這是一個好方法……
面向對象是一個大話題。 可以寫一本關于它的書,但我會堅持在文章的狹小范圍內。 或最多有兩篇有關 OO 的常規文章和 Python 中的 OO 文章。
## 一般的面向對象
面向對象技術大約在 60 年代后期,但直到 90 年代初才在開發人員中獲得了發展空間。 我們將學習以下四個主要原則:
* 封裝
* 數據抽象
* 繼承
* 多態
如果我想模擬現實生活,我會說 OO 就像一家餐館。 您可以有兩種類型:一種可以在柜臺上找到食物,也可以用食物自助服務。 另一個是您進餐的地方,它是由專業服務準備并帶給您的。
帶有自助服務的第一個版本是命令式語言使用的東西(例如 C 或簡單的 Python 腳本),在這里每個人都可以訪問所有內容,并且他們可以使用他們想要的東西。 在這種情況下,有時會將碗碟留在桌子上,因為帶回碗碟是客戶的工作。
第二個版本是 OO。 在那里您可以封裝功能,并且只能訪問那些公開可用的部分。 如果您已經使用 Java 或 C++ 開發過,您可能會知道公開,受保護和私有訪問的概念。 在這種情況下,通過員工來獲取食物并帶回餐具。 他們知道從何處,何處放東西可以得到什么,而最終用戶并不需要了解一切。
如果我們回頭看面向對象,那么我們可以說一類是一個對象的定義,一個對象是指定類的實例。
一個類定義了未來對象具有的屬性和函數,以及該語言是否使用訪問限制,您可以在類定義中告訴公眾可以訪問哪些部分,該類的擴展還是僅內部使用。
現在是時候深入研究 OOP 的四大原則了。
### 封裝
封裝是指將數據和函數打包到單個組件中。 但是,在我們的情況下,進入一類,其他編程語言支持其他替代方法。 該類的函數將根據存儲在該類的字段中的數據進行操作。
在某些編程語言中,封裝用于隱藏信息,或更準確地說:限制對數據和函數的訪問。 這些語言包括 C++ 和 Java,例如,您可以在其中使用`private`,`protected`和`public`來限制對字段和方法的訪問。 但是在 Python 中沒有這樣的限制級別。 您可以訪問類的每個字段和函數。
但是,有一個約定沒有寫下來,但是每個 Python 開發人員都知道并且應該知道:名稱以雙下劃線(`__`)開頭的類(字段和函數)的成員應視為私有的,不應調用或訪問。
### 數據抽象
數據抽象強制將類型的抽象屬性與實現細節之間的清晰區分。 抽象屬性是那些使用此數據類型對客戶端可見的屬性(在我們的情況下為類,在其他編程語言中為接口定義),并且實現對客戶端隱藏并為私有。
而且由于實現是私有的,因此可以隨時間更改(例如,使代碼更快),并且客戶端不會注意到此更改,因為抽象保持不變。
好吧,在 Python 中,沒有什么比其他 OO 語言的接口更好。 您只有一個類,這個類有它的字段和功能。 當然,您可以具有一個“公開”函數作為外部代碼的接口,以及一個或多個實現該“公開”函數的邏輯的“私有”函數。 但這不是真正的抽象。
但是,Python 知道用于只讀字段的解決方案,這些字段是通過所謂的“獲取器”方法即時計算的。 當然,對于讀寫字段,Python 也使我們也可以使用“設置器”方法。 我們將在后面看到這兩個示例。
### 繼承
繼承是 OOP 的一項關鍵功能,其中一個類基于另一類的模板/實現(從該類繼承)。 這是一種代碼重用的基本方法,您可以將子類之間的通用函數和信息封裝到一個基類中。
繼承模型有不同類型,但是最常見的兩種是*單繼承*和*多繼承*。 Python 使用**多重繼承**,這意味著一個類可以根據需要擴展任意多個類。
繼承通常與*對象組成*混淆。 有時,新的開發人員會嘗試解決繼承的所有問題,即使繼承應該是對象組合。 對象組合意味著您擁有另一個類的實例的屬性,但是您的類沒有擴展它。 如果您不知道需要哪一個,請記住以下簡單的解決方案:
繼承是 **is-a** 關系,意思是*汽車是車輛*。 對象組成是**與**的關系,意味著*汽車具有車輪*(或至少汽車具有車輪)。
### 多態
在 OOP 中,多態是為多個類型提供單個接口。 在 Python 中,這意味著您希望將超類作為參數(例如,執行`isinstance()`檢查)并在對象上調用該超類的通用方法。 現在,通過多態,將在所使用的子類中執行該方法的實際實現。
```py
>>> class Animal:
... def sound(self):
... raise NotImplementedError
...
>>> class Dog:
... def sound(self):
... print('woof')
...
>>> class Dog(Animal):
... def sound(self):
... print('woof')
...
>>> class Cat(Animal):
... def sound(self):
... print('meow')
...
>>> def animal_sound(animal):
... if isinstance(animal, Animal):
... animal.sound()
... else:
... print("Not an animal, do not know how to make it sound")
...
>>> cat = Cat()
>>> dog = Dog()
>>> animal_sound(dog)
woof
>>> animal_sound(cat)
meow
```
如您在上面的示例中所看到的,`animal_sound`函數驗證該參數是`Animal`,然后調用該特定動物的`sound`方法。
## 什么時候使用 OO?
自然,OO 不是萬能的油。 因此,在開發時應考慮使用 OOP。 在本節中,我將更深入地探討何時應用本章的原理和技術。
確定何時使用面向對象的編程并不容易。 我們必須記住,對象具有數據**和**行為,這使事情變得復雜。 這就是為什么許多 Python 開發人員使用簡單的數據結構(列表,集合,字典)和簡單的函數的原因,除非確實需要額外的層抽象(我也是)。
現在,如果我們看到使用相同數據集調用函數,則可以考慮將數據封裝到一個類中,然后將這些函數添加為類函數以表示行為。
一個簡單的示例就是幾何圖形之外的東西。 在那里,您使用一個 2 元組(一對)來存儲點。 點列表代表一個形狀(多邊形)。 因此,您首先要定義一個列表,其中包含一些表示點的對:
```py
triangle = [(2,3), (5,7), (0,0)]
```
現在,如果您要計算該三角形的周長,可以編寫一個如下所示的函數:
```py
import math
def perimeter(points):
perimeter = 0
points_extended = points + [points[0]]
for i in range(len(points)):
perimeter += math.sqrt((points_extended[i][0] - points_extended[i+1][0])**2 + (points_extended[i][1] - points_extended[i+1][1])**2)
return perimeter
```
到達這一點之后,您可能會感覺到有一個對象封裝了三角形的所有點(數據)和周長函數(行為)。 如果您想得更多,可以將三角形點的 x 和 y 坐標封裝到另一個對象中,然后將兩個點的距離計算添加到該對象中。
Python 中有一些類可用于此封裝。
在下一篇文章中,我將深入探討 Python 定義和使用對象(類)的方式,并且我必須事先告訴您還有許多您無法想象的方式。
- JavaBeginnersTutorial 中文系列教程
- Java 教程
- Java 教程 – 入門
- Java 的歷史
- Java 基礎知識:Java 入門
- jdk vs jre vs jvm
- public static void main(string args[])說明
- 面向初學者的 Java 類和對象教程
- Java 構造器
- 使用 Eclipse 編寫 Hello World 程序
- 執行順序
- Java 中的訪問修飾符
- Java 中的非訪問修飾符
- Java 中的數據類型
- Java 中的算術運算符
- Java 語句初學者教程
- 用 Java 創建對象的不同方法
- 內部類
- 字符串構建器
- Java 字符串教程
- Java 教程 – 變量
- Java 中的變量
- Java 中的局部變量
- Java 中的實例變量
- Java 引用變量
- 變量遮蓋
- Java 教程 – 循環
- Java for循環
- Java 教程 – 異常
- Java 異常教程
- 異常處理 – try-with-resources語句
- Java 異常處理 – try catch塊
- Java 教程 – OOPS 概念
- Java 重載
- Java 方法覆蓋
- Java 接口
- 繼承
- Java 教程 – 關鍵字
- Java 中的this關鍵字
- Java static關鍵字
- Java 教程 – 集合
- Java 數組教程
- Java 集合
- Java 集合迭代器
- Java Hashmap教程
- 鏈表
- Java 初學者List集合教程
- Java 初學者的Map集合教程
- Java 初學者的Set教程
- Java 初學者的SortedSet集合教程
- Java 初學者SortedMap集合教程
- Java 教程 – 序列化
- Java 序列化概念和示例
- Java 序列化概念和示例第二部分
- Java 瞬態與靜態變量
- serialVersionUID的用途是什么
- Java 教程 – 枚舉
- Java 枚舉(enum)
- Java 枚舉示例
- 核心 Java 教程 – 線程
- Java 線程教程
- Java 8 功能
- Java Lambda:初學者指南
- Lambda 表達式簡介
- Java 8 Lambda 列表foreach
- Java 8 Lambda 映射foreach
- Java 9
- Java 9 功能
- Java 10
- Java 10 獨特功能
- 核心 Java 教程 – 高級主題
- Java 虛擬機基礎
- Java 類加載器
- Java 開發人員必須知道..
- Selenium 教程
- 1 什么是 Selenium?
- 2 為什么要進行自動化測試?
- 3 Selenium 的歷史
- 4 Selenium 工具套件
- 5 Selenium 工具支持的瀏覽器和平臺
- 6 Selenium 工具:爭霸
- 7A Selenium IDE – 簡介,優點和局限性
- 7B Selenium IDE – Selenium IDE 和 Firebug 安裝
- 7C Selenium IDE – 突破表面:初探
- 7D Selenium IDE – 了解您的 IDE 功能
- 7E Selenium IDE – 了解您的 IDE 功能(續)。
- 7F Selenium IDE – 命令,目標和值
- 7G Selenium IDE – 記錄和運行測試用例
- 7H Selenium IDE – Selenium 命令一覽
- 7I Selenium IDE – 設置超時,斷點,起點
- 7J Selenium IDE – 調試
- 7K Selenium IDE – 定位元素(按 ID,名稱,鏈接文本)
- 7L Selenium IDE – 定位元素(續)
- 7M Selenium IDE – 斷言和驗證
- 7N Selenium IDE – 利用 Firebug 的優勢
- 7O Selenium IDE – 以所需的語言導出測試用例
- 7P Selenium IDE – 其他功能
- 7Q Selenium IDE – 快速瀏覽插件
- 7Q Selenium IDE – 暫停和反射
- 8 給新手的驚喜
- 9A WebDriver – 架構及其工作方式
- 9B WebDriver – 在 Eclipse 中設置
- 9C WebDriver – 啟動 Firefox 的第一個測試腳本
- 9D WebDriver – 執行測試
- 9E WebDriver – 用于啟動其他瀏覽器的代碼示例
- 9F WebDriver – JUnit 環境設置
- 9G WebDriver – 在 JUnit4 中運行 WebDriver 測試
- 9H WebDriver – 隱式等待
- 9I WebDriver – 顯式等待
- 9J WebDriver – 定位元素:第 1 部分(按 ID,名稱,標簽名稱)
- 9K WebDriver – 定位元素:第 2 部分(按className,linkText,partialLinkText)
- 9L WebDriver – 定位元素:第 3a 部分(按cssSelector定位)
- 9M WebDriver – 定位元素:第 3b 部分(cssSelector續)
- 9N WebDriver – 定位元素:第 4a 部分(通過 xpath)
- 9O WebDriver – 定位元素:第 4b 部分(XPath 續)
- 9P WebDriver – 節省時間的捷徑:定位器驗證
- 9Q WebDriver – 處理驗證碼
- 9R WebDriver – 斷言和驗證
- 9S WebDriver – 處理文本框和圖像
- 9T WebDriver – 處理單選按鈕和復選框
- 9U WebDriver – 通過兩種方式選擇項目(下拉菜單和多項選擇)
- 9V WebDriver – 以兩種方式處理表
- 9W WebDriver – 遍歷表元素
- 9X WebDriver – 處理警報/彈出框
- 9Y WebDriver – 處理多個窗口
- 9Z WebDriver – 最大化窗口
- 9AA WebDriver – 執行 JavaScript 代碼
- 9AB WebDriver – 使用動作類
- 9AC WebDriver – 無法輕松定位元素? 繼續閱讀...
- 10A 高級 WebDriver – 使用 Apache ANT
- 10B 高級 WebDriver – 生成 JUnit 報告
- 10C 高級 WebDriver – JUnit 報表自定義
- 10D 高級 WebDriver – JUnit 報告自定義續
- 10E 高級 WebDriver – 生成 PDF 報告
- 10F 高級 WebDriver – 截屏
- 10G 高級 WebDriver – 將屏幕截圖保存到 Word 文檔
- 10H 高級 WebDriver – 發送帶有附件的電子郵件
- 10I 高級 WebDriver – 使用屬性文件
- 10J 高級 WebDriver – 使用 POI 從 excel 讀取數據
- 10K 高級 WebDriver – 使用 Log4j 第 1 部分
- 10L 高級 WebDriver – 使用 Log4j 第 2 部分
- 10M 高級 WebDriver – 以無頭模式運行測試
- Vue 教程
- 1 使用 Vue.js 的 Hello World
- 2 模板語法和反應式的初探
- 3 Vue 指令簡介
- 4 Vue Devtools 設置
- 5 數據綁定第 1 部分(文本,原始 HTML,JavaScript 表達式)
- 6 數據綁定第 2 部分(屬性)
- 7 條件渲染第 1 部分(v-if,v-else,v-else-if)
- 8 條件渲染第 2 部分(v-if和v-show)
- 9 渲染列表第 1 部分(遍歷數組)
- 10 渲染列表第 2 部分(遍歷對象)
- 11 監聽 DOM 事件和事件修飾符
- 12 監聽鍵盤和鼠標事件
- 13 讓我們使用簡寫
- 14 使用v-model進行雙向數據綁定
- 15 表單輸入綁定
- 18 類綁定
- Python 教程
- Python 3 簡介
- Python 基礎知識 - 又稱 Hello World 以及如何實現
- 如何在 Windows 中安裝 python
- 適用于 Windows,Mac,Linux 的 Python 設置
- Python 數字和字符串
- Python 列表
- Python 集
- Python 字典
- Python 條件語句
- Python 循環
- Python 函數
- 面向對象編程(OOP)
- Python 中的面向對象編程
- Python 3 中的異常處理
- Python 3:猜數字
- Python 3:猜數字 – 回顧
- Python 生成器
- Hibernate 教程
- Hibernate 框架基礎
- Hibernate 4 入門教程
- Hibernate 4 注解配置
- Hibernate 4 的實體關系
- Hibernate 4 中的實體繼承模型
- Hibernate 4 查詢語言
- Hibernate 4 數據庫配置
- Hibernate 4 批處理
- Hibernate 4 緩存
- Hibernate 4 審計
- Hibernate 4 的并發控制
- Hibernate 4 的多租戶
- Hibernate 4 連接池
- Hibernate 自舉