# Function
By 楊翔宇 (極速車神大佬)
---
## 什麼是 Function ?
----
### 國中學過的 Function:
$f(x) = 3x^2 + 5x - 7$
$f(2) = ?$
- 代入 2
- 得到 $f(2) = 3 \cdot 2^2 + 5 \cdot 2 - 7 = 15$
----
### 程式的 Function 又是什麼 ?
- 不只是數字運算,還是一系列程式碼的包裝
- 舉個做菜的例子
- 做菜的 Function 可能叫做 `make_pasta()`
- 這個 Function 可能包含了以下步驟:
1. 煮水
2. 加入義大利麵
3. 煮到軟硬適中
4. 撈起來瀝乾
5. 加入醬料再炒一次
----
### 為什麼要使用 function (?)
- 可以讓程式碼更簡潔、重複用很方便
- 要煮很多次義大利麵的話...
- 有很多別人寫好的 function!
- 例如:`print()`, `input()`, `len()`, `range()`, `math.sqrt()`, ...
- 或者你跟別人一起寫,大家都寫 function,這樣就可以互相呼叫對方的 function
---
## Function 的語法
----
```python
def function_name(parameters):
# function body
return result
```
- `def` 是定義 function 的關鍵字
- `function_name` 是 function 的名稱,可以自己取
- `parameters` 是 function 的參數,可以有多個,也可以沒有
- `function body` 是 function 的內容,可以是多行程式碼
- `return` 是 function 的回傳值,可以沒有
----
### 使用方法
用剛才的 $f(x)$ 舉個例子:
注意 function 的建立和使用是分開的,先建立 function 再使用
```python
def f(x):
result = 3 * x * x + 5 * x - 7
return result
print(f(2)) # 輸出 15
```
----
### Argument (參數) & Parameter (引數)
在 function 中,argument 跟 parameter 可以讓我們在不同的情況下做不同的事情
- Parameter 是 function 定義時的變數名稱
- Argument 是 function 呼叫時傳入的值
```python
def f(x):
result = 3 * x * x + 5 * x - 7
return result
print(f(2)) # 輸出 17
```
- 在這裡,`x` 是 parameter,而 `2` 是 argument
----
Argument 跟 parameter 可以沒有,也可以有多個,但是要注意順序和數量要對應
```python
def f(x, y):
result = 3 * x * x + 5 * y - 7
return result
print(f(2, 3)) # 輸出 20
```
- 在這裡,`x` 和 `y` 是 parameters,而 `2` 和 `3` 是 arguments
----
練習 [比24還要好笑的笑話](https://tioj.sprout.tw/contests/51/problems/711)
----
### Return value (回傳值)
Return value 是 function 執行完後回傳的結果,可以讓我們在其他地方使用這個結果。
也可以沒有 return value,如果沒有 return value,預設會回傳 `None`
----
```python
def f(x):
return 3 * x * x + 5 * x - 7
result = f(2) # Return value 是 15
print(result) # 輸出 15
```
如果沒有回傳值:
```python
def f(x):
print(3 * x * x + 5 * x - 7)
result = f(2) # Return value 是 None
print(result) # 輸出 None
```
----
### 也可以有多個
其實就是回傳一個 tuple
```python
def f(x):
return 3 * x * x + 5 * x - 7, 2 * x + 1
result = f(2) # Return value 是 (15, 5)
print(result) # 輸出 (15, 5)
```
----
練習 [哪裡買TELSA電動車卡便宜](https://tioj.sprout.tw/contests/51/problems/666)
---
## 更多關於 Function
### Default argument
我們可以在建立 function 的時候設定 default argument,這樣可以用較少的 parameter 來呼叫 function
```python
def f(x, y=0):
return 3 * x * x + 5 * y - 7
print(f(2)) # 輸出 5,因為 y 預設為 0
print(f(2, 3)) # 輸出 20,因為 y 被設定為 3
```
----
要注意 default argument 的位置,必須放在 non-default argument 的後面
```python
def f(x=0, y):
return 3 * x * x + 5 * y - 7
```
會拿到 `SyntaxError: parameter without a default follows parameter with a default`
----
### Keyword argument
我們可以在使用 function 的時候用 `kwarg=value` 的方式來指定 argument,這樣就不需要按照 parameter 的順序來傳入 argument,而且也更清楚
```python
def f(x, y=1, z=2):
return 3 * x * x + 5 * y - z
print(f(2)) # 輸出 15,因為 y 預設為 1,z 預設為 2
print(f(2, z=3)) # 輸出 14
print(f(2, y=4, z=5)) # 輸出 27
'''
不正確的用法
f() # TypeError: f() missing 1 required positional argument: 'x'
f(z=3) # TypeError: f() missing 1 required positional argument: 'x'
f(y=4, 2) # SyntaxError: positional argument follows keyword argument
'''
```
---
## Recursion (遞迴)
可以在 function 裡面呼叫自己 !
用費氏數列 $1, 1, 2, 3, 5...$ 作為例子
```python
def fibonacci(n):
if n == 1 or n == 2:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(5)) # 輸出 5
```
----
解析一下:
- fibonacci(5) 會呼叫 fibonacci(4) 和 fibonacci(3)
- fibonacci(4) 會呼叫 fibonacci(3) 和 fibonacci(2)
- fibonacci(3) 會呼叫 fibonacci(2) 和 fibonacci(1)
- fibonacci(2) 會回傳 1
- fibonacci(1) 會回傳 1
- fibonacci(2) 會回傳 1
- fibonacci(3) 會回傳 fabonacci(2) + fibonacci(1) = 1 + 1 = 2
- fibonacci(4) 會回傳 fibonacci(3) + fibonacci(2) = 2 + 1 = 3
- fibonacci(5) 會回傳 fibonacci(4) + fibonacci(3) = 3 + 2 = 5
----
這裡帶大家用遞迴寫一個 $1+2+3+...+n$ 的 function
```python
def sum_n(n):
if n == 0:
return 0
else:
return n + sum_n(n - 1)
print(sum_n(5)) # 輸出 15
```
----
### 小練習
[[超簡單] 階乘?](https://tioj.sprout.tw/contests/51/problems/99)
---
## 變數 scope
----
變數主要有分 Local 跟 Global
官方說法:
> What are the rules for local and global variables in Python? In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global.
----
> 怎麼分辨 local 跟 global 變數呢?如果在 function 裡面只有被 reference 過的話,那會是 global。如果有在 function 裡面被 assign 的話,那是 local,除非你在 function 裡面用 `global` 關鍵字宣告它是 global。
----
global 代表這個變數跟 function 外的變數是同個東西,如果更改了這個變數的值,那 function 外的變數也會跟著改變。local 變數沒有這種特性。
這裡的 reference 跟 assign 又分別是什麼?
----
```python
x = 3
def set_x():
x = 4 # 這裡是 assign,因為我們給 x 一個新的值 4,所以 x 是 local 變數
set_x()
print(x) # 還是輸出 3
```
----
```python
x = 3
def set_x():
global x
x = 4 # 這裡是 assign,但因為我們明確使用 `global` 關鍵字,所以 x 是 global 變數
set_x()
print(x) # 輸出 4
```
----
id() 可以確認變數的記憶體位置,global 變數的 id() 是不會改變的,而 local 變數的 id() 是會改變的。
----
```python
x = 3
def set_x():
x = 4 # 這裡是 assign,因為我們給 x 一個新的值 4,所以 x 是 local 變數
print(f'Function 裡面 x 的 id: {id(x)}') # local x 的 id
print(f'Function 外面 x 執行 set_x () 前的 id: {id(x)}') # global x 的 id
set_x()
print(f'Function 外面 x 執行 set_x () 後的 id: {id(x)}') # global x 的 id
print(x) # 還是輸出 3
```
----
```python
x = 3
def set_x():
global x
x = 4 # 這裡是 assign,因為我們給 x 一個新的值 4,所以 x 是 global 變數
print(f'Function 裡面 x 的 id: {id(x)}') # global x 的 id
print(f'Function 外面 x 執行 set_x () 前的 id: {id(x)}') # global x 的 id
set_x()
print(f'Function 外面 x 執行 set_x () 後的 id: {id(x)}') # global x 的 id
print(x) # 輸出 4
```
----
```python
x = 3
def set_x(x):
print(f'Function 裡面 assign x 前的 id: {id(x)}') # 這裡還是 global
x = 4 # 這裡是 assign,所以 x 是 local 變數
print(f'Function 裡面 assign x 後的 id: {id(x)}') # local x 的 id
print(f'Function 外面 x 執行 set_x () 前的 id: {id(x)}') # global x 的 id
set_x()
print(f'Function 外面 x 執行 set_x () 後的 id: {id(x)}') # global x 的 id
print(x) # 還是輸出 3
```
---
## Mutable 跟 Immutable 的變數
前幾堂課有提過! 我們來講在 function 裡面 mutable 跟 immutable 變數的差異
----
```python
def add(x):
x = x + 1 # 這裡是 assign,因為我們給 x 一個新的值,所以 x 是 local 變數
x = 3
add(x)
print(x) # 輸出 3
```
----
但是如果我們用 mutable 的變數呢?
```python
def append_list(l):
l.append(4) # 這裡是 reference,因為我們沒有給 l 一個新的值,而是對 l 做修改,所以 l 是 global 變數
l = [1, 2, 3]
append_list(l)
print(l) # 輸出 [1, 2, 3, 4]
```
----
因此要注意! 並不是所有在 function 裡面被 assign 的變數都是 local 變數,如果是 mutable 的變數,就算是 reference,還是會影響到 global 變數的值。
---
## lambda function
----
基本上就是一個沒有名字的 function,可以用來寫一些簡單的 function
```python
def multiply_type1(x, y):
return x * y
multiply_type2 = lambda x, y: x * y
print(multiply_type1(2, 3)) # 輸出 6
print(multiply_type2(2, 3)) # 輸出 6
```
----
也可以搭配參數傳遞 (一般來說 lambda function 會用在一些需要 function 作為參數的情況)
```python
def apply_function(func, x, y):
return func(x, y)
def multiply_type1(x, y):
return x * y
print(apply_function(multiply_type1, 2, 3)) # 輸出 6
print(apply_function(lambda x, y: x * y, 2, 3)) # 輸出 6
```
---
## 結語
function 其實大家現在看起來不像是一個很有用的東西
確實他沒有立即性的幫助,但 function 卻是在真實世界程式裡面不可或缺的元素!
(個人認為重要的點在於把一大串程式碼包成 function 可以很方便的管理!)
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Noto+Sans+TC:wght@100..900&display=swap');
:root {
--r-code-font: "JetBrains Mono", monospace;
--r-main-font: "Inter", "Noto Sans TC", sans-serif;
--r-heading-font: "Inter", "Noto Sans TC", sans-serif;
--r-heading-text-transform: none;
--r-main-font-size: 32px;
}
.reveal-viewport {
backdrop-filter: blur(64px);
background:
radial-gradient(circle at top left, #3398, #0000 50%),
radial-gradient(circle at bottom right, #9938, #0000 50%),
#000d;
}
.reveal .slides {
text-align: left;
}
.reveal .slides .slide:not(.title-slide) {
height: 80%;
}
.reveal .slides .slide .slide-body {
height: 80%;
display: flex;
flex-direction: column;
justify-content: center;
}
.reveal div.sourceCode {
margin: 0;
min-height: 0;
background: transparent;
display: flex;
flex-direction: column;
}
.reveal pre {
all: unset;
min-height: 0;
display: flex;
flex-direction: column;
}
.reveal code {
font-size: .8em;
padding: .2em;
border: 1px solid #fff3;
border-radius: .2em;
background-color: #0003;
}
.reveal .sourceCode code {
font-size: .6em;
padding: 1em;
overflow: scroll;
}
.reveal blockquote {
display: flex;
flex-direction: column;
background: transparent;
box-shadow: none;
}
.reveal blockquote p {
margin: 0;
}
.reveal blockquote::before {
content: "❝";
font-size: 2em;
line-height: 0;
margin-left: -1em;
margin-bottom: -.25em;
}
.reveal blockquote::after {
content: "❞";
font-size: 2em;
line-height: 0;
text-align: right;
}
.reveal blockquote + p {
text-align: right;
}
</style>
{"title":"Function","description":"Here is the cleaned Markdown version of the presentation with all the `` tags removed.","contributors":"[{\"id\":\"6a375517-4167-4b7c-a983-1e595a29262c\",\"add\":23972,\"del\":14945,\"latestUpdatedAt\":1774163446207}]"}