# Python函數、模組與套件(5)
### ***數學上的函數是一段算式,而電腦裡的函數是一段程式碼***
### ***by 幻宇***
在這一篇,我們會介紹兩個主題,分別是:
- 函數(function)
- 模組(module)與套件(Package)
他們在某種意義上可以說是親戚,只是在運用上和規模上有所不同
## 函數(function)
當一段程式碼的使用次數偏多的時候,我們就可以考慮將它變成函數,方便之後要使用時調用,這樣既可以節省空間也可以節省時間。而函數的另一個使用方式是將程式碼進行分段分工,讓程式架構明確,這樣可以方便程式的後續作業,例如除錯和功能擴充
### 定義函數
函數的建立方式稱為定義(define)
```python
def 函數名稱(參數): # 類似數學的f(x)=ax+b
函數主體
return 回傳值
```
`變數`和`return`在有些情況下是可以省略的
### 命名規則
- 必須以字母或底線`_`開頭
- 只能包含字母、數字和底線
- 不能使用保留字(例如`if`、`for`、`return`)
- 函數名稱區分大小寫
通常我們在命名函數時各單字之間會用底線`_`隔開,例如:`function_add()`
### 參數設定
是否要設定參數取決於你是否要將變數丟進函數來運算
```python
a = 1
b = 1
def add():
c = a + b
return c
print(add())
# 2
```
在上面這個例子中,我們可以發現,我們沒給`add()`任何參數,但依然得到了回傳值`2`,這是因為若沒有設定參數函數會直接調用外部同名變數來進行運算,但反之,若設定了參數則會優先調用參數,例子如下
```python
a = 1
b = 1
def add(a, b):
c = a + b
return c
print(add())
#### 因為沒給參數值所以系統報錯
Traceback (most recent call last):
File "c:\Users\hogyu\Desktop\test1.py", line 6, in <module>
print(add())
^^^^^
TypeError: add() missing 2 required positional arguments: 'a' and 'b'
####
```
**補充1**:有一種寫法是`add(a=1,b=1)`,把值和參數寫在一起方便理解
### 回傳設定
有時函數並不需要回傳數值時,就可以不設定回傳,若無明確`return`,函數默認返回`None`
```python
def pri():
print("123")
pri()
# 123
```
### 變數調用
前面提到在特殊情況下,函數可以直接調用外部變數來做使用,而在這裡我們要反其道而行從外部調用內部變數
```python
a = 1
b = 1
def add(a, b):
c = a + b
return c
print(c)
```
以上為錯誤示範,你啥都調不出來,因為`c`未定義,為什麼會這樣呢?
這裡就要提到**全域變數**和**局域變數**的觀念了
在這裡我們想要調出來的`c`就屬於局域變數,它只生活在函數的小世界裡
而外部的`a`和`b`兩個變數則為全域變數,因此我們只要讓`c`具有全域變數的身分就可以調用了
```python
a = 1
b = 1
def add(a, b):
global c # 讓 c 變成全域變數
c = a + b
return c
print(c)
```
但當你想說加一個`global`能搞定時,系統又潑了你一桶冷水,為什麼呢?
其實原因很簡單,因為你的函數還沒運行過啊,內部程式碼根本就沒執行過
```python
b = 1
def add(a, b):
global c
c = a + b
return c
add(a, b)
print(c)
# 2
```
函數執行過後就可以調用`c`啦
### 可變與不可變參數
- 不可變類型(如整數、字串)在函數內改變,不影響外部
- 可變類型(如列表、字典)在函數內改變,會影響外部
```python
# 不可變類型
def str_add(str):
str = str + "4"
str = "123"
str_add(str)
print(str)
# 123
# 可變類型
def list_add(list):
list.append(4)
numbers = [1, 2, 3]
list_add(numbers)
print(numbers)
# [1, 2, 3, 4]
```
### 函數進階用法
這部分就先不細講
- 匿名函數(Lambda): 使用`lambda`定義簡短的匿名函數
```
lambda 參數1, 參數2, ...: 函數主體
```
範例:
```python
add = lambda x, y: x + y
print(add(3, 5))
# 8
```
- 嵌套函數:函數內可以定義其他函數
- 可以將函數作為參數傳遞或作為回傳值返回
- 遞迴函數: 函數可以調用自身,但必須設置脫離條件避免無窮遞迴
## 模組(Module)與套件(Package)
在這裡我們只會簡單介紹其概念和一些常用的模組和套件
### 概念
當我們在開發大型應用程式時,如果沒有適當的組織程式碼,除了會降低開發的效率外,也不易於維護,所以模組(Module)化就顯得相當的重要,讓程式碼能夠透過引用(導入)的方式來重複使用
但是隨著專案模組(Module)的增加,將難以管理及問題的追蹤,這時候就能將模組(Module)打包成套件(Package),利用其階層式的結構來彈性規劃模組(Module)
如果想要知道更詳細的內容可以去看這篇:
[解析Python模組(Module)和套件(Package)的概念](https://www.learncodewithmike.com/2020/01/python-module-and-package.html)
### 常見的模組和套件
- `os`:操作系統相關功能(如檔案、目錄操作)
- `time`/`datetime`:處理時間和日期
- `random`:生成隨機數或隨機選取
- `keyboard`:偵測鍵盤動作
- `turtle`:2D繪圖
- `pygame`:開發2D遊戲應用
- `pyinstaller`:將Python程式打包成執行檔
這裡只講了幾個對初學者來說比較簡單的模組和套件,之後有空的話,我會在寫相關教學
### 模組和套件引用(導入)方法
要使用模組或套件就要先確定是否有安裝該模組或套件,有些模組或套件是在安裝Python時就會一起安裝的,而有些則是要自己手動安裝
安裝方法是在終端機中輸入
```
pip install 模組或套件名稱
```
確認安裝好後就可以在程式內引用了
引用(導入)語法
```python
# 導入整個套件或模組
import 套件或模組名稱
# 引用套件內的模組
from 套件 import 模組
# 但如果是直接導入完整的套件
# 就不需要再引用套件內的模組了
```
## 總結
Python 的函數、模組與套件的存在不僅讓程式碼更加簡潔,還提高了程式的可讀性與可維護性。透過函數,我們能夠避免重複編寫相同的程式碼,而模組與套件則進一步將功能性程式碼組織起來,讓開發者能以結構化的方式管理程式碼,並在不同專案中重複使用已有的功能,這大幅提高了開發效率。總之,函數、模組與套件的使用是現代程式開發中的核心概念,有助於創建高效且可擴展的應用程式
## [下一篇](https://hackmd.io/@Huanyu763/Python基礎教學結語)
## [回到主頁](https://hackmd.io/@Huanyu763/home)