函式

  • 重複使用程式,第一個步驟是函式,它是一種有名稱且獨立的程式片段
  • 函式可以取用任何數量與類型的輸入參數,並回傳任何數量與類型的輸入結果
  • 可以對函式做兩件事:
    • 定義它
    • 呼叫它

定義 Python 函式

  1. 輸入 def、函式名稱、用括號來框住函式的輸入參數,最後加上一個冒號(:)
  2. 函式名稱的命名規則與變數名稱一樣(必須以字母或_開頭,裡面只能使用字母、數字、或 _ )

先定義,並呼叫一個沒有參數的程式

  1. 定義時使用括號與冒號:即使函數沒有參數,還是需要在定義時使用括號與冒號
  2. 縮排:接下來的幾行程式都必須縮排 → 就像在 if 陳述式下面將程式縮排一樣
  3. 使用 pass 陳述式:Python 需要使用 pass 陳述式來說明「這個函式不會做任何事情」。它相當於 "這一頁是故意空白的"
>>> def do_nothing():    # def 函式名稱():
    pass

>>> do_nothing()         # 呼叫這個函式,只要輸入它的名稱與括號
>>>

定義並呼叫參數,但是會印出一個單字的函式

>>> def 函式名稱():
        print('文字')

>>> 函式名稱()
文字
>>> def make_a_sound():    # 呼叫 make_a_sound()函式時,Python 會執行它的定義裡面的程式
    print('quack')         # 印出一個字,並返回主程式

>>> make_a_sound()
quack

沒有參數,但是會回傳一個值的函式

  1. 嘗試一個沒有參數,但是會回傳一個值的函式
  2. 可以呼叫這個函式,並使用 if 來測試它的回傳值
  3. 與 while 一樣,將函式與 if 及迴圈等測試式結合
>>> def 函數名稱():         # 嘗試一個沒有參數,但是會回傳一個值的函式
    return True

>>> if 函數名稱():          # 呼叫這個函式,並使用 if 來測試它的回傳值
        print('文字1')
    else:
        print('文字2')
>>> def agree():
    return True

>>> if agree():
        print('Splendid!')
    else:
        print('That was unexpected.')

Splendid!

定義函式 + 引數 + return 陳述式

  1. 定義函式,它有一個參數
  2. 它會使用 return 陳述式來將參數傳給呼叫方
  3. 引數:在呼叫函式時,傳給它的值
  4. 如果你在呼叫函式時有使用引數,這些引數的值都會被複製到函式裡面的對應參數
>>> def echo(anything):                # 定義函式 echo(),它有一個「參數」,稱為 anything
    return anything '' anything        # 使用 return 陳述式來將 anything 傳給呼叫方兩次,並在它們之間加上空格

>>>
>>> echo('Rumplestiltskin')            # 呼叫 echo(),並傳入引數字串 'Rumplestiltskin'
'Rumplestiltskin Rumplestiltskin'      # 引數字串'Rumplestiltskin',這個值會被複製到 echo() 裡面的參數 anything,並回傳給呼叫方(在這裡會複製兩個,並加上空格)
>>> def commentary(color):             # 寫一個函式,它會使用一個輸入引數(輸入字串參數),並且不會對它做任何實際的事情
    if color == 'red':
        return "It's a tomato."
    elif color == 'green':
        return "It's a green pepper."
    elif color == 'bee purple':
        return "I don't know what it is, but only bees can see it."
    else:
        return "I've never heard of the color " color "."
>>> comment = commentary('blue').       # 呼叫函式 commentary(),並傳入引數 'blue'
  • commentary() 這個函式會做到下列的事情:
    • 指派 'blue' 值給函式內部的 color 參數
    • 執行 if-elif-else 邏輯鍊
    • 回傳一個字串
    • 指派字串給變數 comment
>>> print(comment)
I've never heard of the color blue.

函式沒有明確地呼叫 return,呼叫方會得到 None 這個結果

  • 函式可以取用任何數量、任何類型的「輸入引數」包括零
  • 它可以回傳任何數量、任何類型的「輸出結果」(包括零)
  • 如果函式沒有明確地呼叫 return,呼叫方會得到 None 這個結果
>>> do_nothing()
>>> print(do_nothing())
None

None 很好用

None 當成布林計算時,被視為 false

  • None 是一個特殊的 python 值,它在沒有東西可說時,保留一個位置
  • 它與布林 False 不一樣,但是當你將它當成布林值來計算時,它會被視為 false
>>> 變數 = None
>>> if 變數:
        print("文字1")
    else:
        print("文字2")

文字2
>>> thing = None
>>> if thing:
        print("It's some thing")
    else:
        print("It's no thing")

It's no thing

區分 None 與布林值 False,可以使用 Python 的 is 運算子

  • 區分 None 與布林值 False,這看起來差異不大,但在 Python 中非常重要
  • 需要 None 來區分:「遺漏了值(misssing value)」與「空值(empty value)」
  • 不等於 None,都是False,但它們不等於 None:零值的整數或浮點數、空字串('')、串列([])、tuple((,))、字典({})與集合(set())
>>> if 變數 is None:
        print("文字1")
    else:
        print("文字2")

文字1
>>> if thing is None:
        print("It's nothing")
    else:
        print("It's something")

It's nothing
>>> def is_none(thing):
    if thing is None:
        print("It's None")
    elif thing:
        print("It's True")
    else:
        print("It's False")

>>> is_none(None)
It's None

>>> is_none(True)
It's True

>>> is_none(False)
It's False

>>> is_none(0)
It's False

>>> is_none(0.0)
It's False

>>> is_none(())
It's False

>>> is_none([])
It's False

>>> is_none({})
It's False

>>> is_none(set())
It's False

位置引數

  • 與許多語言相較之下,Python 處理函式引數的方式異常靈活
  • 最常見的引數類型是位置引數,它們的值會被依序複製對應的參數

用位置引數建立一個字典,並將它回傳

以下函式會用它的位置引數建立一個字典,並將它回傳

>>> def 變數(引數1, 引數2, 引數3):
        return {'參數名稱1': 參數1, '參數名稱2': 參數2, '參數名稱3': 參數3}

>>> 變數('引數4', '引數5', '引數6')
{'參數名稱1': '引數4', '參數名稱2': '引數5', '參數名稱3': '引數6'}
>>> def menu(wine, entree, dessert):
    return {'Wine': wine, 'entree': entree, 'dessert': dessert}

>>> menu('chardonnay', 'chicken', 'cake')
{'Wine': 'chardonnay', 'entree': 'chicken', 'dessert': 'cake'}

位置引數的缺點:必須記得每一個位置的意思

如果忘記,並且在呼叫menu()時,將 wine 放在最後一個引數傳入,而不是第一個,這一餐會截然不同

>>> def menu(wine, entree, dessert):
    return {'Wine': wine, 'entree': entree, 'dessert': dessert}

>>> menu('beef', 'bagel', 'bordeaux')
{'Wine': 'beef', 'entree': 'bagel', 'dessert': 'bordeaux'}

關鍵字引數

避免搞不清楚引數,可以用引數的「對應參數名稱」來指定引數

  • 為了避免發生避免搞不清楚引數,可以用引數的「對應參數名稱」來指定引數
  • 即使它們在「函式中定義的順序」不一樣也不會產生問題
>>> def 變數(引數1, 引數2, 引數3):
        return {'參數名稱1': 參數1, '參數名稱2': 參數2, '參數名稱3': 參數3}

>>> 變數(參數名稱1='引數1', 參數名稱2='引數2', 參數名稱3='引數3')
{'參數名稱1': '引數1', '參數名稱2': '引數2', '參數名稱3': '引數3'}

混合使用位置與關鍵字引數

如果呼叫函式時,要同時使用位置與關鍵字引數,位置引數必須放在前面

>>> def 變數(引數1, 引數2, 引數3):
        return {'參數名稱1': 參數1, '參數名稱2': 參數2, '參數名稱3': 參數3}

>>> 變數(引數1, 參數名稱2='引數2', 參數名稱3='引數3')
{'參數名稱1': '引數1', '參數名稱2': '引數2', '參數名稱3': '引數3'}

指定預設參數值

  • 可以指定預設的參數值,在呼叫方沒有提供對應的引數的時候使用
  • 有時這種聽起來很平凡的功能會非常實用
  • 預設的引數值會在函式被定義的時候計算,而不是執行的時候
  • Python 新手經常出現的錯誤(有時稍具經驗的人也會出錯),就是使用可變的資料類型,例如串列或字典,來作為預設引數
>>> def 變數(引數1, 引數2, 引數3='參數值'):
        return {'參數名稱1': 參數1, '參數名稱2': 參數2, '參數名稱3': 參數3}

>>> 變數('引數4', '引數5')
{'參數名稱1': '引數4', '參數名稱2': '引數5', '參數名稱3': '參數值'}

>>> 變數('引數6', '引數7', '引數8')
{'參數名稱1': '引數6', '參數名稱2': '引數7', '參數名稱3': '引數8'}
>>> def menu(wine, entree, dessert='pudding'):
    return {'wine': wine, 'entree': entree, 'dessert': dessert}

>>> menu('chardonnay', 'chicken')                        # 呼叫 menu()時,不使用 dessert 引數,會使用預設參數值
{'wine': 'chardonnay', 'entree': 'chicken', 'dessert': 'pudding'}

>>> menu('dunkelfelder', 'duck', 'doughnut')             # 提供引數的話,函式就會使用它,而不是預設值
{'wine': 'dunkelfelder', 'entree': 'duck', 'dessert': 'doughnut'}

【範例】函式執行 → 使用全新空字串 → 加入引數 → 印出單一項目的串列

>>> def buggy(arg, result=[]):           # 預期 buggy() 函式在每次執行時,都會使用一個全新的空字串 result(bug!!)
    result.append(arg)                   # 全新的result 空字串,對它加入 arg 引數
    print(result)                        # 印出一個單一項目的串列

>>> buggy('a')                           # 串列只有對第一次呼叫函式時,是空的
['a']
>>> buggy('b')                           # 第二次呼叫時,result 仍然存有之前呼叫時留下來的項目
['a', 'b']
>>> def works(arg):                      # 如果將它寫成這樣,就可以正常動作
    result = []
    result.append(arg)
    return result                        # 寫成print(result)也可以正常動作

>>> works('a')
['a']
>>> works('b')
['b']
>>> def nonbuggy(arg, result=None):      # 修正方式:傳入其他的東西,來說明「函式是否第一次被呼叫」
    if result is None:
        result = []
    result.append(arg)
    print(result)

>>> nonbuggy('a')
['a']
>>> nonbuggy('b')
['b']

用 * 來收集引數

Python 沒有指標(如果你曾經使用 C 或 C++,可能會認為 Python 中的星號(*)會做指標之類的事情)

「函式的參數」使用星號 → 將「可變數量」的「潛在引數群組化」 → 變成參數值的 Tuple

>>> def print_args(*args):                                           # 函數的參數使用星號,星號會將「可變數量」的「潛在引數群組化」,變成一個參數值的tuple
    print('Positional argument tuple:', args)                        # args 是個參數 tuple,它是被傳入 print_args()函式的引數所產生的

>>> print_args()                                                     # 呼叫它時不傳入引數,*args 裡面就不會有任何東西
Positional argument tuple: ()

>>> print_args(3, 2, 1, 'wait!', 'uh...')                            # 提供引數,它會被印成 args tuple
Positional argument tuple: (3, 2, 1, 'wait!', 'uh...')

編寫 print() 這類會接收「任意數量」引數的函式 → 星號(*)這很好用

  • 如果你的函式也需要用到位置引數,就把 *args 放在最後面,抓取剩下的引數
  • 其實在使用 * 時,並不需要呼叫 tuple 參數 args,這種做法只是 Python 的慣例
>> def print_more(required1, required2, *args):                      # 函式也需要用到位置引數,就把 *args 放在最後面,抓取剩下的引數
    print('Need this one:', required1)
    print('Need this one too:', required2)
    print('All th rest:', args)

>>> print_more('cap', 'gloves', 'scarf', 'monocle', 'mustache wax')
Need this one: cap
Need this one too: gloves
All th rest: ('scarf', 'monocle', 'mustache wax')

用 ** 來收集關鍵字引數

  • 如果混合使用「位置參數」與 args 以及 *kwargs,就必須按照這個順序來排列它們
  • 如同 args,其實不需要呼叫關鍵字參數 kwargs,這只是一種慣例
>>> def 變數(**kwargs):                                                            # 使用兩個星號(**)來將「關鍵字引數群組化」
        print('引數名稱:', kwargs)

>>> 變數(參數名稱1='引數1', 參數名稱2='引數2', 參數名稱3='引數3')
引數名稱: {'引數名稱1: '引數1', '引數名稱2: '引數2', '引數名稱3: '引數3'}
>> def print_kwargs(**kwargs):                                                     # 定義函式 print_kwargs(),印出它的關鍵字引數
    print('Keyword arguments:', kwargs)                                            # 在函式內,kwargs 是個字典

>>> print_kwargs(wine='merlot', entree='mutton', dessert='macaroon')               # 呼叫函式,使用一些關鍵字引數
Keyword arguments: {'wine': 'merlot', 'entree': 'mutton', 'dessert': 'macaroon'}   # 變成一個字典,其中「引數名稱」是「鍵」,「值」是對應的「字典值」

文件字串(docstring)

  • Zen of Python 可讀性必須列入考慮
  • 可以將「文件」指派給「函式的定義式」→ 【做法】在函式內文的開頭加入一個字串

函式的「文件字串(docstring)」

>>> def 函式名稱(參數):
        '文件字串'
        return 參數
>>> def echo(anything):
    'echo returns its input argument'
    return anything

可以加入很長的文件字串,甚至加入豐富格式

>>> def print_if_true(thing, check):
Prints the first argument if a second argument is true.
The operation is:
    1. Check whether the *second* argument is true.
    2. If it is, print the *first* argument.
```
if check:
    print(thing)

##印出函式的文件字串【呼叫 Python help() 函式】

```python
>>> def echo(anything):
    'echo returns its input argument'
    return anything

>>> help(echo)                                    # 印出函式的文件字串,可以呼叫 Python help()函式
Help on function echo in module __main__:

echo(anything)                                    # 傳遞「函式的名稱」來取得一串的「引數」,以及具備良好格式的文字字串
    echo returns its input argument

只想看原始的文件字串,不想要有格式

doc是函式的文件字串的變數名稱(在本書 p111 "在名稱中使用與_" 會解釋使用這些底線的原因)

>>> def echo(anything):
    'echo returns its input argument'
    return anything

>>> print(echo.__doc__)
echo returns its input argument

results matching ""

    No results matching ""