# 4. 模組與類別
模組的好處:
1. 抽象層的封裝與隔離
2. 儲存物件的狀態
3. 擁有自己的名稱空間
4. 容易重用、功能拆分,更容易透過團隊協同開發專案
## 4.1 建立模組
Python的「.py」檔本身就是一個模組,所以模組是Python最自然的抽象層。
透過`import`指令就可以把模組內的變數、物件和函式引入使用;當`import`某個模組會使該被指定的「.py」檔被載入時,Python直譯器會為這個檔案建立一個module實例(instance),並賦予一個名字可以用來參考它。
##### `dir()`
`dir()`函式可以列出一個模組內有哪些名稱:
```
import math
dir(math)
```
> 如果呼叫`dir()`函式的時候沒有帶入模組名稱,會查詢目前所在模組的名稱。
### 4.1.1 `from ... import ...`
也可以用下面的方式將指定的模組內的名稱匯入:
```
for foo import x
print(x)
import foo
print(foo.x)
```
如果是使用`*`結尾,將會匯入模組內所有名稱,如果有變數不想被匯入,可以加上底線開頭,例如:
```
x = 1
_y = 2 # 將不會被匯入
z = 3
```
```
from foo import *
print(x)
print(_y) # NameError
```
##### `__all__`
定義`__all__`清單可以直接指定可以被`import`的名稱,例如:
```
__all__ = ['x', 'y']
```
變數`x`、`y`將被匯入。
### 4.1.2 `del 模組名稱`
`del`除了可以刪除變數外,也可以刪除模組,因為透過`import`建立的名稱,其實也是建立變數,因此可以將透過`import`進來的模組刪除。
```
import foo
del foo
from foo import x
del x
```
> `del`只是刪除名稱,而不是將模組刪除
##### `sys.modules`
想要知道目前載入的名稱與實力有哪些,可以透過`sys.modules`,例如:
```
import sys
import foo
'foo' in sys.modules
del foo
sys.modules['foo'].x
```
> `import`也可以加上`if`條件式,用來在不同的情況下`import`不同的模組
## 4.2 類別
### 4.2.1 定義類別
```
class MyClass:
pass
myClass = MyClass()
```
### 4.2.2 定義方法
```
class MyClass:
def plus(self, a, b):
return a + b
myClass = MyClass()
print(myClass.plus(10, 20))
```
在類別內所有的方法第一個參數都是`self`
### 4.2.3 定義`__init__()`方法
`__init()`方法可以將該類別的初始化流程都定義在裡面,該方法在建立類別物件的時候會自動被呼叫。
```
class MyClass:
def __init__(self):
self.x = 99
self.y = 88
def show(self):
print(self.x)
print(self.y)
myClass = MyClass()
myClass.show()
```
> 請注意`__init__()`方法前後都是兩個底線。
##### `__str()__`方法
透過定義`__str__()`方法,可以在該物件透過呼叫`str()`函式時輸出自訂的字串,例如:
```
class MyClass:
def __str__(self):
return 'Hello, Class!'
myClass = MyClass()
print(str(myClass))
```
> 請注意,該方法一定要回傳一個字串。
## 4.3 實作
### 4.3.1 題目
開發一個學生成績管理系統,有三個主要功能:
1. 管理學生成績
2. 查詢學生成績
3. 關於
##### 管理學生成績
有兩個子功能:
1. 新增學生成績:學號、姓名、國文、英文、數學
2. 刪除學生成績:可以輸入學號或姓名來刪除
##### 查詢學生成績
有兩個子功能:
1. 依學號查詢
2. 顯示全部成績
> 1. 成績查詢皆會自動加總分數
> 2. 子選單需要有回主選單功能
> 3. 主選單需要有離開功能
### 4.3.2 程式碼
##### 無函式版:
```
grades = {} # 空的dict(字典)
while True:
print('===================')
print('學生成績管理系統')
print('===================')
print('1. 管理學生成績')
print('2. 查詢學生成績')
print('3. 關於')
print('4. 離開')
cmd = input('==>')
if cmd == '1': # 管理學生成績
while True:
print('===================')
print('子選單: 管理學生成績')
print('===================')
print('1. 新增學生成績')
print('2. 刪除學生成績')
print('3. 回主選單')
sub_cmd = input('==>')
if sub_cmd == '1': # 新增學生成績
num = input('請輸入學號: ')
name = input('請輸入姓名: ')
mandiran = int(input('請輸入國文成績: ')) # int()轉成數字
math = int(input('請輸入數學成績: '))
english = int(input('請輸入英文成績: '))
# 新增一筆成績
grades[num] = [name, mandiran, math, english]
#print(grades) # for 開發時除錯用
print('新增完成!')
elif sub_cmd == '2': # 刪除學生成績
num = input('請輸入要刪除成績的學號: ')
if num in grades.keys():
del grades[num]
print('刪除完成!')
else:
print('查無此人!')
#print(grades) # for 開發時除錯用
elif sub_cmd == '3': # 回主選單
break
elif cmd == '2': # 查詢學生成績
while True:
print('===================')
print('子選單: 查詢學生成績')
print('===================')
print('1. 依學號查詢')
print('2. 顯示全部成績')
print('3. 回主選單')
sub_cmd = input('==>')
if sub_cmd == '1': # 依學號查詢
num = input('請輸入要查詢成績的學號: ')
if num in grades.keys():
grade = grades[num]
print('學號', num, ', ', grade[0], '的成績: 國文=', grade[1], \
', 數學=', grade[2], ', 英文=', grade[3], ', 總分: ', \
grade[1] + grade[2] + grade[3])
else:
print('查無此人!')
elif sub_cmd == '2': # 顯示全部成績
if len(grades) == 0:
print('無學生成績資料')
else:
for num, grade in grades.items():
print('學號', num, ', ', grade[0], '的成績: 國文=', grade[1], \
', 數學=', grade[2], ', 英文=', grade[3], ', 總分: ', \
grade[1] + grade[2] + grade[3])
elif sub_cmd == '3': # 回主選單
break
elif cmd == '3': # 關於
print('學生成績管理系統')
print('版本: 0.01')
print('日期: 2020-08-01')
print('開發者: Aaron Ho')
elif cmd == '4': # 離開
break
else:
print('輸入錯誤!')
```
##### 函式版
students_system.py
```
grades = {}
def student_system():
while True:
print('-------------------')
print('學生成績管理系統')
print('-------------------')
print('1. 管理學生成績')
print('2. 查詢學生成績')
print('3. 結束')
c = input('=> ')
if c == '1':
func_1()
elif c == '2':
func_2()
elif c == '3':
break
else:
print('輸入錯誤!')
def func_1():
while True:
print('-------------------')
print('管理學生成績')
print('-------------------')
print('1. 新增學生成績')
print('2. 刪除學生成績')
print('3. 回主功能表')
c = input('=> ')
if c == '1':
add_grade()
elif c == '2':
del_grade()
elif c == '3':
break
else:
print('輸入錯誤!')
def func_2():
while True:
print('-------------------')
print('查詢學生成績')
print('-------------------')
print('1. 依學號查詢')
print('2. 查詢全部成績')
print('3. 回主功能表')
c = input('=> ')
if c == '1':
find_grade()
elif c == '2':
show_grades()
elif c == '3':
break
else:
print('輸入錯誤!')
def add_grade():
n = input('請輸入學號: ')
name = input('請輸入學生姓名: ')
mandrain = input('請輸入國文成績: ')
math = input('請輸入數學成績: ')
english = input('請輸入英文成績: ')
grades[n] = [name, mandrain, math, english]
print('新增完成!')
def del_grade():
n = input('請輸入要刪除的學號: ')
if n in grades.keys():
del grades[n]
print('刪除完成.')
else:
print('查無此人.')
def find_grade():
n = input('請輸入要查詢的學號: ')
if n in grades.keys():
grade = grades[n]
print('學號: ', n, ', ', grade[0], '的成績: 國文=', grade[1], ', 數學=', grade[2], ', 英文=', grade[3])
else:
print('查無此人.')
def show_grades():
if len(grades) == 0:
print('無學生成績.')
return
for n, grade in grades.items():
print('學號: ', n, ', ', grade[0], '的成績: 國文=', grade[1], ', 數學=', grade[2], ', 英文=', grade[3])
```
main.py
```
import student_system
st = student_system
st.student_system()
```
#### 練習
1. 請將學生成績管理系統改為類別版本。