# 面相對象基礎語法
## 目標
- `dir` 內置函數
- 定義簡單的類(只包含方法)
- 方法中的 `self` 參數
- 初始化方法
- 內置方法和屬性
## 01. `dir` 內置函數(知道)
- 在 `Python` 中 **對象幾乎是無所不在的**,我們之前學習的 **變量**、**數據**、**函數** 都是對象
在 `Python` 中可以使用以下兩個方法驗證:
1. 在 **標識符** / **數據** 后輸入一個 `.`,然后按下 `TAB` 鍵,`iPython` 會提示該對象能夠調用的 **方法列表**
2. 使用內置函數 `dir` 傳入 **標識符** / **數據**,可以查看對象內的 **所有屬性及方法**
**提示** `__方法名__` 格式的方法是 `Python` 提供的 **內置方法 / 屬性**,稍后會給大家介紹一些常用的 內置方法 / 屬性
| 序號 | 方法名 | 類型 | 作用 |
| :--: | :--------: | :--: | :------------------------------------------- |
| 01 | `__new__` | 方法 | **創建對象**時,會被 **自動** 調用 |
| 02 | `__init__` | 方法 | **對象被初始化**時,會被 **自動** 調用 |
| 03 | `__del__` | 方法 | **對象被從內存中銷毀**前,會被 **自動** 調用 |
| 04 | `__str__` | 方法 | 返回**對象的描述信息**,`print` 函數輸出使用 |
**提示** 利用好 `dir()` 函數,在學習時很多內容就不需要死記硬背了
## 02. 定義簡單的類(只包含方法)
> **面向對象** 是 **更大** 的 **封裝**,在 **一個類中 封裝 多個方法**,這樣 **通過這個類創建出來的對象,就可以直接調用這些方法了**!
### 2.1 定義只包含方法的類
- 在 `Python` 中要定義一個只包含方法的類,語法格式如下:
```python
class 類名:
def 方法1(self, 參數列表):
pass
def 方法2(self, 參數列表):
pass
```
- **方法** 的定義格式和之前學習過的**函數** 幾乎一樣
- 區別在于第一個參數必須是 `self`,大家暫時先記住,稍后介紹 `self`
> 注意:**類名** 的 命名規則 要符合 **大駝峰命名法**
### 2.2 創建對象
- 當一個類定義完成之后,要使用這個類來創建對象,語法格式如下:
```python
對象變量 = 類名()
```
### 2.3 第一個面向對象程序
**需求**
- **小貓** 愛 **吃** 魚,**小貓** 要 **喝** 水
**分析**
1. 定義一個貓類 `Cat`
2. 定義兩個方法 `eat` 和 `drink`
3. 按照需求 —— 不需要定義屬性

```python
class Cat:
"""這是一個貓類"""
def eat(self):
print("小貓愛吃魚")
def drink(self):
print("小貓在喝水")
tom = Cat()
tom.drink()
tom.eat()
```
#### 引用概念的強調
> 在面向對象開發中,**引用**的概念是同樣適用的!
- 在 `Python` 中使用類 **創建對象之后**,`tom` 變量中 仍然記錄的是 **對象在內存中的地址**
- 也就是 `tom` 變量 **引用** 了 **新建的貓對象**
- 使用 `print` 輸出 **對象變量**,默認情況下,是能夠輸出這個變量 **引用的對象** 是 **由哪一個類創建的對象**,以及 **在內存中的地址**(**十六進制表示**)
> 提示:在計算機中,通常使用 **十六進制** 表示 **內存地址**
>
> - **十進制** 和 **十六進制** 都是用來表達數字的,只是表示的方式不一樣
> - **十進制** 和 **十六進制** 的數字之間可以來回轉換
- `%d` 可以以 **10 進制** 輸出數字
- `%x` 可以以 **16 進制** 輸出數字
#### 案例進階 —— 使用 Cat 類再創建一個對象
```python
lazy_cat = Cat()
lazy_cat.eat()
lazy_cat.drink()
```
> 提問:`tom` 和 `lazy_cat` 是同一個對象嗎?
## 03. 方法中的 `self` 參數
### 3.1 案例改造 —— 給對象增加屬性
- 在Python中,要給對象設置屬性,非常的容易,但是不推薦使用
- 因為:對象屬性的封裝應該封裝在類的內部
- 只需要在 **類的外部的代碼** 中直接通過 `.` 設置一個屬性即可
> 注意:這種方式雖然簡單,但是不推薦使用!
```python
tom.name = "Tom"
...
lazy_cat.name = "大懶貓"
```
### 3.2 使用 `self` 在方法內部輸出每一只貓的名字
> 由 **哪一個對象** 調用的方法,方法內的 `self` 就是 **哪一個對象的引用**
- 在類封裝的方法內部,`self` 就表示 **當前調用方法的對象自己**
- **調用方法時**,程序員不需要傳遞 `self` 參數
- 在方法內部
- 可以通過 `self.` **訪問對象的屬性**
- 也可以通過 `self.` **調用其他的對象方法**
- 改造代碼如下:
```python
class Cat:
def eat(self):
print("%s 愛吃魚" % self.name)
tom = Cat()
tom.name = "Tom"
tom.eat()
lazy_cat = Cat()
lazy_cat.name = "大懶貓"
lazy_cat.eat()
```

- 在 **類的外部**,通過 `變量名.` 訪問對象的 **屬性和方法**
- 在 **類封裝的方法中**,通過 `self.` 訪問對象的 **屬性和方法**
## 04. 初始化方法
### 4.1 之前代碼存在的問題 —— 在類的外部給對象增加屬性
- 將案例代碼進行調整,**先調用方法 再設置屬性**,觀察一下執行效果
```python
tom = Cat()
tom.drink()
tom.eat()
tom.name = "Tom"
print(tom)
```
- 程序執行報錯如下:
```
AttributeError: 'Cat' object has no attribute 'name'
屬性錯誤:'Cat' 對象沒有 'name' 屬性
```
**提示**
- 在日常開發中,不推薦在類的外部給對象增加屬性。
- 如果**在運行時,沒有找到屬性,程序會報錯**。
- 對象應該包含有哪些屬性,應該 **封裝在類的內部**。
### 4.2 初始化方法
- 當使用 ` 類名()
`創建對象時,會自動執行以下操作:
1. 為對象在內存中 **分配空間** —— 創建對象
2. 為對象的屬性 **設置初始值** —— 初始化方法(`init`)
- 這個 **初始化方法** 就是 `__init__` 方法,`__init__` 是對象的**內置方法**
> `__init__` 方法是 **專門** 用來定義一個類 **具有哪些屬性的方法**!
在 `Cat` 中增加 `__init__` 方法,驗證該方法在創建對象時會被自動調用
```python
class Cat:
"""這是一個貓類"""
def __init__(self):
print("初始化方法")
```
### 4.3 在初始化方法內部定義屬性
- 在 `__init__` 方法內部使用 `self.屬性名 = 屬性的初始值` 就可以 **定義屬性**
- 定義屬性之后,再使用 `Cat` 類創建的對象,都會擁有該屬性
```python
class Cat:
def __init__(self):
print("這是一個初始化方法")
# 定義用 Cat 類創建的貓對象都有一個 name 的屬性
self.name = "Tom"
def eat(self):
print("%s 愛吃魚" % self.name)
# 使用類名()創建對象的時候,會自動調用初始化方法 __init__
tom = Cat()
tom.eat()
```
### 4.4 改造初始化方法 —— 初始化的同時設置初始值
- 在開發中,如果希望在創建對象的同時,就設置對象的屬性,可以對`__init__
`方法進行改造
1. 把希望設置的屬性值,定義成 `__init__` 方法的參數
2. 在方法內部使用 `self.屬性 = 形參` 接收外部傳遞的參數
3. 在創建對象時,使用 `類名(屬性1, 屬性2...)` 調用
```python
class Cat:
def __init__(self, name):
print("初始化方法 %s" % name)
self.name = name
...
tom = Cat("Tom")
...
lazy_cat = Cat("大懶貓")
...
```
## 05. 內置方法和屬性
| 序號 | 方法名 | 類型 | 作用 |
| :--: | :-------: | :--: | :------------------------------------------- |
| 01 | `__del__` | 方法 | **對象被從內存中銷毀**前,會被 **自動** 調用 |
| 02 | `__str__` | 方法 | 返回**對象的描述信息**,`print` 函數輸出使用 |
### 5.1 `__del__` 方法(知道)
- 在 `Python` 中
- 當使用 `類名()` 創建對象時,為對象 **分配完空間**后,**自動** 調用 `__init__` 方法
- 當一個 **對象被從內存中銷毀** 前,會 **自動** 調用 `__del__` 方法
- **應用場景**
- `__init__` 改造初始化方法,可以讓創建對象更加靈活
- `__del__` 如果希望在對象被銷毀前,再做一些事情,可以考慮一下 `__del__` 方法
- **生命周期**
- 一個對象從調用 `類名()` 創建,生命周期開始
- 一個對象的 `__del__` 方法一旦被調用,生命周期結束
- 在對象的生命周期內,可以訪問對象屬性,或者讓對象調用方法
```python
class Cat:
def __init__(self, new_name):
self.name = new_name
print("%s 來了" % self.name)
def __del__(self):
print("%s 去了" % self.name)
# tom 是一個全局變量
tom = Cat("Tom")
print(tom.name)
# del 關鍵字可以刪除一個對象
del tom
print("-" * 50)
```
### 5.2 `__str__` 方法
- 在 `Python` 中,使用 `print` 輸出 **對象變量**,默認情況下,會輸出這個變量 **引用的對象** 是 **由哪一個類創建的對象**,以及 **在內存中的地址**(**十六進制表示**)
- 如果在開發中,希望使用 `print` 輸出 **對象變量** 時,能夠打印 **自定義的內容**,就可以利用 `__str__` 這個內置方法了
> 注意:`__str__` 方法必須返回一個字符串
```python
class Cat:
def __init__(self, new_name):
self.name = new_name
print("%s 來了" % self.name)
def __del__(self):
print("%s 去了" % self.name)
def __str__(self):
return "我是小貓:%s" % self.name
tom = Cat("Tom")
print(tom)
```
- linux基礎
- 01_Python基礎課程安排
- 02_操作系統(科普章節)
- 03_操作系統的發展史(科普章節)
- 04_文件和目錄(理解)
- 05_Ubuntu圖形界面入門
- 06_常用Linux命令的基本使用
- 07_Linux終端命令格式
- 08_文件和目錄常用命令
- 09_遠程管理常用命令
- 10_用戶權限相關命令
- 11_系統信息相關命令
- 12_其他命令
- python基礎
- 01_認識 Python
- 02_第一個Python 程序
- 03_PyCharm的初始設置(知道)
- 04_多文件項目的演練
- 05_注釋
- 06_算數運算符
- 07_程序執行原理(科普)
- 08_變量的基本使用
- 09_變量的命名
- 10_判斷(if)語句
- 11_運算符
- 12_循環
- 13_函數基礎
- 14_高級變量類型
- 15_綜合應用——名片管理系統
- 16_變量進階(理解)
- 17_函數進階.md
- 面向對象
- 01_面向對象(OOP)基本概念
- 02_類和對象
- 03_面向對象基礎語法
- 04_面向對象封裝案例
- 05_面向對象封裝案例 II