---
# System prepended metadata

title: 4. 模組與類別
tags: [python]

---

# 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. 請將學生成績管理系統改為類別版本。


