---
###### tags: `Sprout`
---
<style>
.reveal {
font-size: 32px;
}
</style>
# Function
###### 資訊之芽py班 2023
###### 黃千睿
---
## Intro
----
### 什麼是 function
* 一系列動作的包裝
* 把動作定義好,方便後續使用
* 舉例來說,如果我要[畫一個圓](https://www.youtube.com/watch?v=EXNCQDi03mQ&ab_channel=95Ld)
* 先畫一個頭
* 然後再擦掉一點點畫像的細部
* 然後1,2,3
* 一個圓,好了
----

----
* 每次都要詳述流程很麻煩
* 我們就把這一系列動作包裝成「畫圓」
* function 就跟「畫圓」一樣,把一系列動作包裝起來
---
## function 的語法
----
### 基本語法
```python=
def say_hello(): #函數名稱
print("Hello") #函數內容
say_hello() #呼叫函數
```
----
### parameters & arguments
* 如果我們希望 function 能根據不同的情形做不同的事情呢?
* 可以善用 parameters(參數) 和 arguments(引數)
```python=
def say_hello(a):
print(f"Hello from {a}")
say_hello("Enzo")
```
* 在這個例子中,a 就是parameter,"Enzo" 就是argument
----
* 一個 function 可以有多個參數,但需要注意他們的順序
```python=
def say_hello(a, b):
print(f"Hello from {a} to {b}")
say_hello("Alice", "Bob")
```
* 或是可以利用 key=value 的方式來表達,這樣就不用考慮順序
```python=
say_hello(a = "Alice", b = "Bob")
say_hello(a = "Bob", b = "Alice")
```
----
* 當我們把int, float, string 傳進 function 時,原本變數的值不會被改變
```python=
def f1(num):
num += 1
x = 87
f1(x)
print(x)
```
* 如果是 list, dict, set 等,則會改變原本的值
```python=
def f2(l):
l[0] += 1
y = [87, 88, 89]
f2(y)
print(y)
```
----
### Why?
* id() 回傳變數存在電腦內的位置
* 回傳的 id 一樣,代表我們會對存在在同個位置的同個東西操作
```python=
def f1(num):
num += 1
print(f"id of num is {id(num)}")
def f2(l):
l[0] += 1
print(f"id of l is {id(l)}")
x = 87
print(f"id of x is {id(x)}")
f1(x)
y = [87,88,89]
print(f"id of y is {id(y)}")
f2(y)
print(x, y)
```
* 所以 function 內外的 list 其實是同一個
----
### 回傳值
* 如果想要讓 function 跑完可以產出一個值讓我們後續可以使用,那我們可以善用 function 的回傳值 (return value)
```python=
def factorial(n):
result = 1
for i in range(1, n + 1):
result *= i
return result
print(factorial(5)/(factorial(2) * factorial(3)))
```
----
* function 遇到 return 後就會直接中止,可以善用這個性質
```python=
def is_prime(number):
for i in range(2, number):
if number % i == 0:
return False
return True
print(is_prime(17))
```
----
### 定義 parameter 和 return value 的資料型態
```python=
def say_hello(a: str, b: str) -> str:
print(f"Hello from {a} to {b}")
say_hello("Alice", "Bob")
```
* python 不會檢查 parameter 和 return value 的資料型態是否如同宣稱
* 這個只是提供人類看得,python interpreter 不會理會
* 不知道大作業會不會用到 🙃
----
### 我們已經見過的 function 們
```python=
sum([1,2,3])
min(2,3)
max(4,5)
```
```python=
type(sum)
type(min)
type(max)
type(print) # builtin_function_or_method
```
----
### 練習
[比24還要好笑的笑話](https://neoj.sprout.tw/problem/3051)
----
### 透過 function ,我們可以...
1. 把需要重複使用的一系列動作包裝起來
2. 呼叫 function 只需要知道它的參數、回傳值和功能是什麼,不用管function內部的實作方式
3. 讓你的程式變得更簡潔,別人也比較容易看懂
```python=
def factorial(n):
result = 1
for i in range(1, n + 1):
result *= i
return result
print(factorial(5)/(factorial(2) * factorial(3)))
```
----
### Questions?
----
### 練習
[哪裡買TELSA電動車卡便宜](https://neoj.sprout.tw/problem/3005/)
---
## Recursive
----
### Recursive (遞迴)的概念
* 在一個 function 內部呼叫自己
* 想想看費波納契數列的例子

----
我們可以這樣做
```python=
def Fibonacci(n):
if n == 0:
return 0
if n == 1:
return 1
return Fibonacci(n-1) + Fibonacci(n-2)
```
----
### 如果想要挑戰...
[超級貓貓星際漫遊3](https://neoj.sprout.tw/problem/3403/)
----
### Questions?
---
## Scope
----
```python=
s = 0
def plus(a,b):
s = a + b
print(f"s before plus: {s}")
plus(1,2)
print(f"s after plus: {s}")
```
為什麼s沒有變化?
----
### Scope (範圍)
function 內的變數有兩種形式
* Global Variable(全域變數):所有地方都能看到的變數
* Local Variable(區域變數):只有 Function 裡面才能看到的變數
function 內的 local variable 跟外面是隔開的,雖然名字一樣但是互不干擾
----
```python=
s = 0
def plus(a,b):
s = a + b
print(f"s before plus: {s}")
plus(1,2)
print(f"s after plus: {s}")
```
所以在這個例子,plus() 中的 s 是 local variable,跟外面同樣名字的變數是隔開的
----
### 那什麼時候會出現 global variable 呢?
----
### 官方說法
>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.
[Reference]( https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python)
----

----
### 白話文
* 如果一個變數在function內沒有被賦值 (只有被reference),那它會被視為 global variable
* 反之,它就是 local variable (除非他被特別宣告成 global variable)
----
### 舉個栗子🌰
```python=
global_var = 1234
def func():
local_var = 5678
print(f"global = {global_var}, local={local_var}")
func()
print(f"global = {global_var}, local={local_var}")
```
在這個例子中,global_var 就是全域變數,local_var 是區域變數
所以最後一行會出錯,因為 function 外看不到 local_var
----
```python=
s = 0
def plus(a,b):
s = a + b
print(f"s before plus: {s}")
plus(1,2)
print(f"s after plus: {s}")
```
再回來看這個例子,因為 plus() 當中 s 這個變數被賦值了,所以就變成 local variable (就算外面也有s這個變數),跟外面同樣名字的變數是隔開的
----
```python=
s = 0
def plus(a,b):
global s
s = a + b
print(f"s before plus: {s}")
plus(1,2)
print(f"s after plus: {s}")
```
我們也可以強制將應該是 local variable 的變數轉成 global variable
----
### Questions?
----
### 懂了之後,告訴你一個小秘密...
以上的狀況只適用於 int, float, bool 等基礎資料型態
至於 list, dict, set 這些資料型態基於跟 parameters & arguments 那段相同的原因,所以不適用
----
```python=
s = [1,2,3]
def plus(a,b):
s[0] = a + b
print(f"s before plus: {s}")
plus(1,2)
print(f"s after plus: {s}")
```
像這樣
----
* 盡可能避免使用 global variable,沒正確使用很容易變成地雷
* 如果你考上台大資工,大一修了P教授的計程,請記得不要在考試的時候使用全域變數 (會哭 🥺)

---
## Lambda Function
----
### Lambda Function 的概念
假如我要寫一個回傳平方的 function
```python=
def square(x):
return x ** 2
print(square(4))
```
明明是很間單的運算,但是空間卻占的有點多
----
### Lambda Function 的概念
可以用 python 特別的lambda function 簡化
```python=
square = lambda x : x ** 2
print(square(4))
```
也可以有多個 parameter
```python=
multiply = lambda a, b : a * b
print(multiply(8,7))
```
---
## 作業
----
沒有作業,大作業加油🎉
{"metaMigratedAt":"2023-06-18T01:11:09.101Z","metaMigratedFrom":"Content","title":"Function","breaks":true,"contributors":"[{\"id\":\"12fd27f5-82a5-4f30-8a85-e747ae0676cf\",\"add\":6536,\"del\":462}]"}