# 8. 函式與遞迴

## I. 函式

### A. 何謂函式?

想必大家應該不陌生，在數學科目中應該多少有接觸到吧！！

![](https://1394144544-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Ma3iO86k0kEA04rPhPo%2Fuploads%2FTb7S0qxSDswwLIV11z5o%2FdgwVeEe.png?alt=media\&token=a96b2c89-e4a5-49a3-908e-aae4cbd0762a)

![](https://1394144544-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Ma3iO86k0kEA04rPhPo%2Fuploads%2FyFBoNE1PWkmSP6LU4EdU%2FoQLB4DH.png?alt=media\&token=58071380-ecde-4c2d-b16f-fb6a76864784)

### B. 為何需要函式?

最主要其實是要將某個流程封裝、模組化，未來若需要進行同樣流程時，我們只需要呼叫這模組即可，程式碼能夠精簡化，也比較美觀

人偶爾會幻想如果有個僕人能幫我做牛做馬的那該有多好啊！！其實函式就像是個專業的僕人，你可以請他幫你完成一些事，不過要記住，他是個專業的僕人，不是萬能的僕人，專業的僕人只會做專業的幾件事喔！

&#x20;                  ![](https://1394144544-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Ma3iO86k0kEA04rPhPo%2Fuploads%2FT4EHlHz4LMQJSH3bRgxH%2FC9lpS1P.png?alt=media\&token=a811b1e7-a2e1-488c-a007-98da65600cfa)                          ![](https://1394144544-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Ma3iO86k0kEA04rPhPo%2Fuploads%2FDU4n9FnzIt7tvF5XdfYa%2FH2IKHtS.png?alt=media\&token=70fc41e6-5ac2-4a15-b948-8a878a63a17a)

### C. 函式的基本結構 <a href="#python-zhong-de-han-shi-jie-gou" id="python-zhong-de-han-shi-jie-gou"></a>

#### 1. 無回傳值、無參數輸入型

```python
def wash_dish():
    print('是!我立刻去洗盤子')
```

#### 2. 無回傳值、有參數輸入型

```python
def wash_dish(x):
    print('是!我立刻去洗',x,'個盤子')
```

#### 3. 有回傳值、無參數輸入型

```python
def wash_dish():
    s = "是!我立刻去洗盤子"
    return s
```

#### 4. 有回傳值、有參數輸入型

```python
def wash_dish(x):
    s = "是!我立刻去洗" + str(x) + "個盤子"
    return s
```

### D. 函式呼叫 <a href="#han-shi-hu-jiao" id="han-shi-hu-jiao"></a>

1\. 既然函式可以視作僕人，呼叫函式的就是主人囉!

2\. 在主人還沒呼叫函式前函式是不會有動作的

<mark style="background-color:red;">3. 函式必須在呼叫前先定義完成</mark>

<mark style="background-color:red;">4. 參數可以有多個，且型態不拘</mark>

#### 1. 無參數的函式

```python
# 函式必須要先定義，但不會做出動作
def wash_dish():
    s = "是!我立刻去洗盤子"
    return s

# 主人開始呼叫函式，這時函式才開始動作
print(wash_dish()) # 是!我立刻去洗盤子
```

#### 2. 單個參數的函式

```python
# 函式必須要先定義，但不會做出動作
def wash_dish(x):
    s = "是!我立刻去洗" + str(x) + "個盤子"
    return s

# 主人開始呼叫函式，這時函式才開始動作
print(wash_dish(5)) # 是!我立刻去洗5個盤子
```

#### 3. 多個參數的函式

```python
def add(a, b):
    return a + b
    
x, y = map(int, input("請輸入兩個整數：").split())
print(add(x, y))
```

> <mark style="background-color:purple;">主人用x與y參數傳給僕人，僕人方相對應的參數視為為a與b</mark>

#### 4. 未知個參數的函式

函式中參數前面加上`*`號，表示可輸入未知筆資料，所輸入的資料將存在陣列(tuple)中

```python
def make_snow_ice(*toppings):
    print('您的雪花冰配料如下：')
    for topping in toppings:
        print(topping)

make_snow_ice('愛玉') # 您的雪花冰配料如下：愛玉
make_snow_ice('愛玉', '花生', '芋圓') # 您的雪花冰配料如下：愛玉 花生 芋圓
```

```python
def make_snow_ice(toppings):
    print('您的雪花冰配料如下：')
    for topping in toppings:
        print(topping)

i = input('請輸入您想要的配料：').split()
make_snow_ice(i)
```

#### 5. 有預設值的參數

```python
# 有預設值的參數
def interest(type, area='Taiwan'):
    print('我的興趣是', type, '最喜歡的地方是', area)

interest('吃飯') # 我的興趣是 吃飯 最喜歡的地方是 Taiwan
interest('吃飯', 'New Zealand') # 我的興趣是 吃飯 最喜歡的地方是 New Zealand
interest(area='New Zealand', type='吃飯') # 我的興趣是 吃飯 最喜歡的地方是 New Zealand
```

#### 6. 函式的相互呼叫

```python
def add(a, b):
    return a+b

def avg(a, b):
    return add(a, b)/2

while 1:
    m, n = map(int, input("請輸入兩個整數：").split())
    print(avg(m,n))
```

```python
def add(a, b):
    return a+b
    
def mul(a, b):
    return a*b

def running(func, arg1, arg2):
    return func(arg1, arg2)

print(running(add, 5, 10)) # 15
print(running(mul, 5, 10)) # 50
```

#### 7. 【補充】閉包(closure)函式

原先沒有closure，我們需要傳遞a, b, x參數，closure可以讓程式設計更有效率，同時未來擴充時，程式碼可以更容易移植

```python
def outer(a, b):
    '''a和b是inner()的環境變數'''
    def inner(x):
        return a*x+b
    return inner
    
f1=outer(1, 2)
f2=outer(3, 4)
print(f1(1)) # 3
print(f2(3)) # 13
```

## II. 遞迴

> 其實就是自己呼叫自己的函式

![](https://1394144544-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Ma3iO86k0kEA04rPhPo%2Fuploads%2FhPjicZyRzBl8CTGakVl2%2Fimage.png?alt=media\&token=0ee993f0-9223-4142-8b8a-597593d7024b)

![](https://1394144544-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Ma3iO86k0kEA04rPhPo%2Fuploads%2FLnmuvI8O9yqAZ8gIXGmw%2Fimage.png?alt=media\&token=35810971-5391-47ec-966b-fe29a5a103cb)

![](https://1394144544-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Ma3iO86k0kEA04rPhPo%2Fuploads%2FjQuAgAZhJvtt1dAtn3nu%2Fimage.png?alt=media\&token=6884dd78-4cb7-4ab7-b4a4-10a28720e5df)

![Recursion(遞迴)](https://1394144544-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Ma3iO86k0kEA04rPhPo%2Fuploads%2FxXDYuAKz4PSxOJxZworV%2Fimage.png?alt=media\&token=618b39c3-a44a-4356-b35f-c8ed15bd6dc3)

### A. 遞迴的必要條件

1. <mark style="background-color:red;">**遞迴關係式(需有回傳 ： 記憶)**</mark>
2. <mark style="background-color:red;">**有個最終停止的點(驚醒)**</mark>

### B. 範例

#### 【範例一】請用遞迴方式計算n層香檳塔共有幾個杯子

<mark style="background-color:green;">觀察</mark>：

1層香檳塔 → 1個杯子

2層香檳塔 → 5個杯子

&#x20;           ......

n層香檳塔 → ?

<mark style="background-color:green;">歸納</mark>：

是否存在遞迴關係式？Ａ：$$S\_n = S\_{n-1} + n × n$$

是否有最終停止的點？A：$$S\_1 = 1$$

<mark style="background-color:green;">程式碼</mark>：

```python
# 遞迴寫法(1)
def sum_champagne_glass(n):
    if n == 1:
        return 1
    else:
        return  sum_champagne_glass(n-1) + n*n
```

```python
# 遞迴寫法(2)
def sum_champagne_glass(n):
    if n == 1:
        return 1
    return  sum_champagne_glass(n-1) + n*n
```

```python
# 迴圈寫法
def sum_champagne_glass(n):
    sum = 0
    for i in range(1, n+1):
        sum += i*i
    return sum

while 1:
    i = int(input("請輸入層數："))
    print('總共有：',sum_champagne_glass(i),'個酒杯')
```

> 遞迴並不是在任何情況下都比迴圈來的好用
>
> 遞迴就只是自己呼叫自己的函式

#### 【範例二】請用遞迴方式計算出n階乘的值

<mark style="background-color:green;">觀察</mark>：

0! → 1

1! → 1

2! → 2

.....

n!  → ?

<mark style="background-color:green;">歸納</mark>：

是否存在遞迴關係式？Ａ：$$F\_{n} = F\_{n-1}  × n$$&#x20;

是否有最終停止的點？A：$$F\_{0} = 1$$

<mark style="background-color:green;">程式碼</mark>：

```python
# 遞迴寫法
def factorial(n):
    if n==0:
        return 1
    return factorial(n-1)*n
    
while 1:
    i = int(input('請輸入您想計算的階乘：'))
    print(factorial(i))
```

```python
# 迴圈寫法
def factorial(n):
    accumulate = 1
    if n==0:
        return 1
    for i in range(2, n+1):
        accumulate *= i
    return accumulate

while 1:
    i = int(input('請輸入您想計算的階乘：'))
    print(factorial(i))
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://simplife.gitbook.io/python/xin-shou-cun/8.-han-shi-yu-di-hui.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
